//++++++++++++++++++++++++++++++++++++++
//[FDXNOW for San Andreas by TheFarckYT]
//++++++++++++++++++++++++++++++++++++++
/*


#include "Common.cfi"
#include "ShadeLib.cfi"
#include "PostEffectsLib.cfi"

// Shader global descriptions
float Script : STANDARDSGLOBAL
<
  string Script =
           "NoPreview;"
           "LocalConstants;"
           "ShaderDrawType = Custom;"
           "ShaderType = PostProcess;"
>; 

sampler2D rainbowSampler = sampler_state
{
  Texture = textures/defaults/glitter_color.dds;
  MinFilter = LINEAR;  
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Texture To Texture technique /////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 texToTexParams0;
float4 texToTexParams1;

////////////////// samplers /////////////////////

///////////////// vertex shader //////////////////

struct vtxOutTexToTex
{
  float4 HPosition  : POSITION;
  float4 baseTC0 : TEXCOORDN;    
  float4 baseTC1 : TEXCOORDN;    
  float4 baseTC2 : TEXCOORDN;    
  float4 baseTC3 : TEXCOORDN;    
  float4 baseTC4 : TEXCOORDN;    
};

vtxOutTexToTex TexToTexVS(vtxIn IN)
{
  vtxOutTexToTex OUT = (vtxOutTexToTex)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  

  OUT.baseTC0.xy = IN.baseTC.xy;
  OUT.baseTC1.xy = IN.baseTC.xy+texToTexParams0.xy;
  OUT.baseTC2.xy = IN.baseTC.xy+texToTexParams0.zw;
  OUT.baseTC3.xy = IN.baseTC.xy+texToTexParams1.xy;
  OUT.baseTC4.xy = IN.baseTC.xy+texToTexParams1.zw; 
  
  return OUT;
}

///////////////// pixel shader //////////////////
pixout TexToTexPS(vtxOutTexToTex IN)
{
  pixout OUT;
  OUT.Color = tex2D(_tex0, IN.baseTC0.xy);    
  return OUT;
}

// With rotated grid sampling (less artifacts). Used for image rescaling
pixout TexToTexSampledPS(vtxOutTexToTex IN)
{
  pixout OUT;

  half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);

  OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)*0.2f;
   
  return OUT;
}


// Version for SSAO z-target
pixout TexToTexSampledAOPS(vtxOutTexToTex IN)
{
  pixout OUT;
      
  half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);
  
  // Use max to prevent artifacts.
  OUT.Color = max(baseColor0, max(max(baseColor1.r, baseColor3.r), max(baseColor2.r, baseColor4.r)));
  //OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)*0.2f;
   
  return OUT;
}

////////////////// technique /////////////////////

technique TextureToTextureResampledAO
{
  pass p0
  {
    VertexShader = CompileVS TexToTexVS();            
    PixelShader = CompilePS TexToTexSampledAOPS();
    CullMode = None;        
  }
}



sampler2D SamplerNoise = sampler_state
{
	Texture   = <texNoise>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;//NONE;
	AddressU  = Wrap;
	AddressV  = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

struct VS_OUTPUT_POST {
	float4 vpos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST {
	float3 pos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;

	float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,1.0);

	OUT.vpos=pos;
	OUT.txcoord.xy=IN.txcoord.xy;

	return OUT;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//--------------------Fast Approximate Anti-Aliasing --------------------------
//         FXAA v2 CONSOLE by TIMOTHY LOTTES @ NVIDIA   
//          Ported to ENBSeries by MysTer92 (Svyatoslav Gampel)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



float4 PS_PostProcess(VS_OUTPUT_POST i) : COLOR
{
	#define FXAA_SUBPIX_SHIFT (1.0/8.0)
	#define FXAA_REDUCE_MIN   (1.0/32.0)
	#define FXAA_REDUCE_MUL   (1.0/16.0)
	#define FXAA_SPAN_MAX     8.0

	half2 rcpFrame = half2(1/ScreenSize.x, 1/(ScreenSize.x/ScreenSize.z));

	half4 posPos;
	posPos.xy = i.txcoord.xy;
	posPos.zw = posPos.xy - (rcpFrame.xy * (0.5 + FXAA_SUBPIX_SHIFT));

	half3 rgbNW = tex2D(SamplerColor, posPos.zw ).xyz;
	half3 rgbNE = tex2D(SamplerColor, posPos.zw + half2(rcpFrame.x, 0.0) ).xyz;
	half3 rgbSW = tex2D(SamplerColor, posPos.zw + half2(0.0, rcpFrame.y) ).xyz;
	half3 rgbSE = tex2D(SamplerColor, posPos.zw +rcpFrame.xy ).xyz;
	half3 rgbM  = tex2D(SamplerColor, posPos.xy).xyz;
       
	half3 luma = half3(0.299, 0.587, 0.114);
	half lumaNW = dot(rgbNW, luma);
	half lumaNE = dot(rgbNE, luma);
	half lumaSW = dot(rgbSW, luma);
	half lumaSE = dot(rgbSE, luma);
	half lumaM  = dot(rgbM,  luma);
       
	half lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
	half lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
       
	half2 dir; 
       
	half lumaNWNE = lumaNW + lumaNE;
	half lumaSWSE = lumaSW + lumaSE;
       
	dir.x = -((lumaNWNE) - (lumaSWSE));
	dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
       
	half dirReduce = max( (lumaSWSE + lumaNWNE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
	half rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
	dir = min(half2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX), max(half2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * rcpFrame.xy;
             
	half3 rgbA = (1.0/2.0) * (tex2D(SamplerColor, posPos.xy + dir * (1.0/3.0 - 0.5) ).xyz + tex2D(SamplerColor, posPos.xy + dir * (2.0/3.0 - 0.5) ).xyz);
	half3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (tex2D(SamplerColor, posPos.xy + dir * (0.0/3.0 - 0.5) ).xyz + tex2D(SamplerColor, posPos.xy + dir * (3.0/3.0 - 0.5) ).xyz);
	half lumaB = dot(rgbB, luma);
     
	if((lumaB < lumaMin) || (lumaB > lumaMax))
 		return half4(rgbA, 1.0);
       
	return float4(rgbB, 1.0);
}

float4 PS_PostProcess_Sharp_Noise(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res = 0;
	float4 tex=0.0;
	tex.xy=IN.txcoord.xy;

	float3 ori = tex2D(SamplerColor, tex).rgb;       // ori = original pixel

	float2 p;
	p.x = 1.0/ScreenSize.x;
	p.y=p.x/ScreenSize.z;

	// -- Gaussian filter --
	//   [ .50, .50, .50]     [ 1 , 1 , 1 ]
	//   [ .50,    , .50]  =  [ 1 ,   , 1 ]
 	//   [ .50, .50, .50]     [ 1 , 1 , 1 ]

    float3 blur_ori = tex2D(SamplerColor, tex + float2(0.5 * p.x,-p.y * offset_bias)).rgb;  // South South East
    blur_ori += tex2D(SamplerColor, tex + float2(offset_bias * -p.x,0.5 * -p.y)).rgb; // West South West
    blur_ori += tex2D(SamplerColor, tex + float2(offset_bias * p.x,0.5 * p.y)).rgb; // East North East
    blur_ori += tex2D(SamplerColor, tex + float2(0.5 * -p.x,p.y * offset_bias)).rgb; // North North West

    //blur_ori += (2 * ori); // Probably not needed. Only serves to lessen the effect.
	
    blur_ori /= 4.0;  //Divide by the number of texture fetches

    //sharp_strength_luma *= 0.666; // Adjust strength to aproximate the strength of pattern 2
	
	// -- Calculate the sharpening --  
	float3 sharp = ori - blur_ori;  //Subtracting the blurred image from the original image
  
	// -- Adjust strength of the sharpening --
	float sharp_luma = dot(sharp, sharp_strength_luma); //Calculate the luma and adjust the strength

	// -- Clamping the maximum amount of sharpening to prevent halo artifacts --
	sharp_luma = clamp(sharp_luma, -sharp_clamp, sharp_clamp);  //TODO Try a curve function instead of a clamp

	// -- Combining the values to get the final sharpened pixel	--
  //float4 done = ori + sharp_luma;    // Add the sharpening to the original.
	float4 done = tex2D(SamplerColor, tex) + sharp_luma;    // Add the sharpening to the input color.

 

	// -- Grain noise
	float origgray=dot(done.xyz, 0.333);
	//origgray=max(origgray, res.z);
	tex.xy=IN.txcoord.xy*16.0 + origgray;
	float4 cnoi=tex2Dlod(SamplerNoise, tex);
	done=lerp(done, (cnoi.x+0.5)*done, NoiseAmount*saturate(1.0-origgray*1.8));


	done.w=1.0;
	return done;
}

technique PostProcess //FXAA
{
   pass P0
   {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_PostProcess_Sharp_Noise();

	FogEnable=FALSE;
	ALPHATESTENABLE=FALSE;
	SEPARATEALPHABLENDENABLE=FALSE;
	AlphaBlendEnable=FALSE;
	FogEnable=FALSE;
	SRGBWRITEENABLE=FALSE;
   }
}

technique PostProcess2 //FXAA
{
   pass P0
   {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_PostProcess();

	FogEnable=FALSE;
	ALPHATESTENABLE=FALSE;
	SEPARATEALPHABLENDENABLE=FALSE;
	AlphaBlendEnable=FALSE;
	FogEnable=FALSE;
	SRGBWRITEENABLE=FALSE;
   }
}

technique PostProcess3 //FXAA
{
   pass P0
   {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_PostProcess_Sharp_Noise();

	FogEnable=FALSE;
	ALPHATESTENABLE=FALSE;
	SEPARATEALPHABLENDENABLE=FALSE;
	AlphaBlendEnable=FALSE;
	FogEnable=FALSE;
	SRGBWRITEENABLE=FALSE;
   }
}

tenchique Volumetric lighting

    pass
    
   Vertex shader = Lighting vs_0_3 VS_PostProcess();
   PixelLighting = Compile ps_3_0 PS PosProcess_Lighting_Sharp_NoisePD();


}

///////////////////////
//	  TECHNIQUES	 //
///////////////////////
technique PostProcess
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessNoise();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess2
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessBlur();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess3
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessSharpen();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess4
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessShift();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}	

technique PostProcess5
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessContrast();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess6
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessVibrance();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess7
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessLumaSharpen();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}
	
technique PostProcess8
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_LevelsPass();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}



/**
 * This can be ignored; its purpose is to support interactive custom parameter
 * tweaking.
 */
float threshold;
float maxSearchSteps;
float maxSearchStepsDiag;

#ifdef SMAA_PRESET_CUSTOM
#define SMAA_THRESHOLD threshold
#define SMAA_MAX_SEARCH_STEPS maxSearchSteps
#define SMAA_MAX_SEARCH_STEPS_DIAG maxSearchStepsDiag
#define SMAA_FORCE_DIAGONALS 1
#endif

// Set the HLSL version:
#define SMAA_HLSL_3 1

// And include our header!
#include "SMAA.h"


/**
 * Input vars and textures.
 */

texture2D colorTex2D;
texture2D depthTex2D;
texture2D edgesTex2D;
texture2D blendTex2D;
texture2D areaTex2D;
texture2D searchTex2D;


/**
 * DX9 samplers.
 */
sampler2D colorTex {
    Texture = <colorTex2D>;
    AddressU  = Clamp; AddressV = Clamp;
    MipFilter = Point; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = true;
};

sampler2D colorTexG {
    Texture = <colorTex2D>;
    AddressU  = Clamp; AddressV = Clamp;
    MipFilter = Linear; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = false;
};

sampler2D depthTex {
    Texture = <depthTex2D>;
    AddressU  = Clamp; AddressV = Clamp;
    MipFilter = Linear; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = false;
};

sampler2D edgesTex {
    Texture = <edgesTex2D>;
    AddressU = Clamp; AddressV = Clamp;
    MipFilter = Linear; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = false;
};

sampler2D blendTex {
    Texture = <blendTex2D>;
    AddressU = Clamp; AddressV = Clamp;
    MipFilter = Linear; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = false;
};

sampler2D areaTex {
    Texture = <areaTex2D>;
    AddressU = Clamp; AddressV = Clamp; AddressW = Clamp;
    MipFilter = Linear; MinFilter = Linear; MagFilter = Linear;
    SRGBTexture = false;
};

sampler2D searchTex {
    Texture = <searchTex2D>;
    AddressU = Clamp; AddressV = Clamp; AddressW = Clamp;
    MipFilter = Point; MinFilter = Point; MagFilter = Point;
    SRGBTexture = false;
};


/**
 * Function wrappers
 */
void DX9_SMAAEdgeDetectionVS(inout float4 position : POSITION,
                             inout float2 texcoord : TEXCOORD0,
                             out float4 offset[3] : TEXCOORD1) {
    SMAAEdgeDetectionVS(position, position, texcoord, offset);
}

void DX9_SMAABlendWeightCalculationVS(inout float4 position : POSITION,
                                      inout float2 texcoord : TEXCOORD0,
                                      out float2 pixcoord : TEXCOORD1,
                                      out float4 offset[3] : TEXCOORD2) {
    SMAABlendWeightCalculationVS(position, position, texcoord, pixcoord, offset);
}

void DX9_SMAANeighborhoodBlendingVS(inout float4 position : POSITION,
                                    inout float2 texcoord : TEXCOORD0,
                                    out float4 offset[2] : TEXCOORD1) {
    SMAANeighborhoodBlendingVS(position, position, texcoord, offset);
}


float4 DX9_SMAALumaEdgeDetectionPS(float4 position : SV_POSITION,
                                   float2 texcoord : TEXCOORD0,
                                   float4 offset[3] : TEXCOORD1,
                                   uniform SMAATexture2D colorGammaTex) : COLOR {
    return SMAALumaEdgeDetectionPS(texcoord, offset, colorGammaTex);
}

float4 DX9_SMAAColorEdgeDetectionPS(float4 position : SV_POSITION,
                                    float2 texcoord : TEXCOORD0,
                                    float4 offset[3] : TEXCOORD1,
                                    uniform SMAATexture2D colorGammaTex) : COLOR {
    return SMAAColorEdgeDetectionPS(texcoord, offset, colorGammaTex);
}

float4 DX9_SMAADepthEdgeDetectionPS(float4 position : SV_POSITION,
                                    float2 texcoord : TEXCOORD0,
                                    float4 offset[3] : TEXCOORD1,
                                    uniform SMAATexture2D depthTex) : COLOR {
    return SMAADepthEdgeDetectionPS(texcoord, offset, depthTex);
}

float4 DX9_SMAABlendingWeightCalculationPS(float4 position : SV_POSITION,
                                           float2 texcoord : TEXCOORD0,
                                           float2 pixcoord : TEXCOORD1,
                                           float4 offset[3] : TEXCOORD2,
                                           uniform SMAATexture2D edgesTex, 
                                           uniform SMAATexture2D areaTex, 
                                           uniform SMAATexture2D searchTex) : COLOR {
    return SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edgesTex, areaTex, searchTex, 0);
}

float4 DX9_SMAANeighborhoodBlendingPS(float4 position : SV_POSITION,
                                      float2 texcoord : TEXCOORD0,
                                      float4 offset[2] : TEXCOORD1,
                                      uniform SMAATexture2D colorTex,
                                      uniform SMAATexture2D blendTex) : COLOR {
    return SMAANeighborhoodBlendingPS(texcoord, offset, colorTex, blendTex);
}


/**
 * Time for some techniques!
 */
technique LumaEdgeDetection {
    pass LumaEdgeDetection {
        VertexShader = compile vs_3_0 DX9_SMAAEdgeDetectionVS();
        PixelShader = compile ps_3_0 DX9_SMAALumaEdgeDetectionPS(colorTexG);
        ZEnable = false;        
        SRGBWriteEnable = false;
        AlphaBlendEnable = false;

        // We will be creating the stencil buffer for later usage.
        StencilEnable = true;
        StencilPass = REPLACE;
        StencilRef = 1;
    }
}

technique ColorEdgeDetection {
    pass ColorEdgeDetection {
        VertexShader = compile vs_3_0 DX9_SMAAEdgeDetectionVS();
        PixelShader = compile ps_3_0 DX9_SMAAColorEdgeDetectionPS(colorTexG);
        ZEnable = false;        
        SRGBWriteEnable = false;
        AlphaBlendEnable = false;

        // We will be creating the stencil buffer for later usage.
        StencilEnable = true;
        StencilPass = REPLACE;
        StencilRef = 1;
    }
}

technique DepthEdgeDetection {
    pass DepthEdgeDetection {
        VertexShader = compile vs_3_0 DX9_SMAAEdgeDetectionVS();
        PixelShader = compile ps_3_0 DX9_SMAADepthEdgeDetectionPS(depthTex);
        ZEnable = false;        
        SRGBWriteEnable = false;
        AlphaBlendEnable = false;

        // We will be creating the stencil buffer for later usage.
        StencilEnable = true;
        StencilPass = REPLACE;
        StencilRef = 1;
    }
}

technique BlendWeightCalculation {
    pass BlendWeightCalculation {
        VertexShader = compile vs_3_0 DX9_SMAABlendWeightCalculationVS();
        PixelShader = compile ps_3_0 DX9_SMAABlendingWeightCalculationPS(edgesTex, areaTex, searchTex);
        ZEnable = false;
        SRGBWriteEnable = false;
        AlphaBlendEnable = false;

        // Here we want to process only marked pixels.
        StencilEnable = true;
        StencilPass = KEEP;
        StencilFunc = EQUAL;
        StencilRef = 1;
    }
}

technique NeighborhoodBlending {
    pass NeighborhoodBlending {
        VertexShader = compile vs_3_0 DX9_SMAANeighborhoodBlendingVS();
        PixelShader = compile ps_3_0 DX9_SMAANeighborhoodBlendingPS(colorTex, blendTex);
        ZEnable = false;
        SRGBWriteEnable = true;
        AlphaBlendEnable = false;

        // Here we want to process all the pixels.
        StencilEnable = true;
    }
}	



#include "Common.cfi"
#include "ShadeLib.cfi"
#include "PostEffectsLib.cfi"

// Shader global descriptions
float Script : STANDARDSGLOBAL
<
  string Script =
           "NoPreview;"
           "LocalConstants;"
           "ShaderDrawType = Custom;"
           "ShaderType = PostProcess;"
>; 

sampler2D rainbowSampler = sampler_state
{
  Texture = textures/defaults/glitter_color.dds;
  MinFilter = LINEAR;  
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
};


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Texture To Texture technique /////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 texToTexParams0;
float4 texToTexParams1;

////////////////// samplers /////////////////////

///////////////// vertex shader //////////////////

struct vtxOutTexToTex
{
  float4 HPosition  : POSITION;
  float2 baseTC0 : TEXCOORDN;    
  float2 baseTC1 : TEXCOORDN;    
  float2 baseTC2 : TEXCOORDN;    
  float2 baseTC3 : TEXCOORDN;    
  float2 baseTC4 : TEXCOORDN;    
};

vtxOutTexToTex TexToTexVS(vtxIn IN)
{
  vtxOutTexToTex OUT = (vtxOutTexToTex)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC0.xy = IN.baseTC.xy;
  OUT.baseTC1.xy = IN.baseTC.xy+texToTexParams0.xy;
  OUT.baseTC2.xy = IN.baseTC.xy+texToTexParams0.zw;
  OUT.baseTC3.xy = IN.baseTC.xy+texToTexParams1.xy;
  OUT.baseTC4.xy = IN.baseTC.xy+texToTexParams1.zw;  

  return OUT;
}

///////////////// pixel shader //////////////////
pixout TexToTexPS(vtxOutTexToTex IN)
{
  pixout OUT;
  OUT.Color=tex2D(_tex0, IN.baseTC0.xy);    
  return OUT;
}

// With rotated grid sampling (less artifacts). Used for image rescaling
pixout TexToTexSampledPS(vtxOutTexToTex IN)
{
  pixout OUT;

  int nQuality = GetShaderQuality();
  if( nQuality == QUALITY_HIGH )
  {
    half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
    half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
    half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
    half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
    half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);
    
    OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)/5.0;     
  }
  else
  {
    OUT.Color = tex2D(_tex0, IN.baseTC0.xy);
  }
    
  
    
  return OUT;
}

pixout TexToTexSampled_3x3(vtxOutTexToTex IN, bool bFirstStep)
{
  pixout OUT;

  float fRes = 0;
  float fMin = 10000;
  float fSumm = 0;
  for(float s = -1; s <= 1; s++)
  for(float t = -1; t <= 1; t++)
  {
    float fWidth = 1.9f - length( float3( s, t, 0 ) );
    float4 vSample = tex2D( _tex0, IN.baseTC0.xy + float2( s/PS_ScreenSize.x, t/PS_ScreenSize.y ) * 1 );
    fRes += (vSample.r ? vSample.r : 1.f) * fWidth;

    if(bFirstStep)
      fMin = min(vSample.r, fMin);
    else
      fMin = min(vSample.g, fMin);

    fSumm += fWidth;
  }
  
  fRes /= fSumm;

  OUT.Color = float4( fRes, fMin, 0, 0 );

  return OUT;
}


// With rotated grid sampling (less artifacts). Used for image rescaling
pixout TexToTexSampledAOPS_3x3_First(vtxOutTexToTex IN)
{
  return TexToTexSampled_3x3(IN, true);
}

// Version for SSAO z-target
pixout TexToTexSampledAOPS_3x3_Second(vtxOutTexToTex IN)
{
  return TexToTexSampled_3x3(IN, false);
}

// Version for SSAO z-target
pixout TexToTexSampledAOPS(vtxOutTexToTex IN)
{
  pixout OUT;
      
  half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);

  OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)/5.0;     

//  OUT.Color = min(baseColor4,(min(baseColor0,baseColor1),min(baseColor2,baseColor3))); 
   
  return OUT;
}

////////////////// technique /////////////////////

technique TextureToTextureResampledAO
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();            
    PixelShader = compile ps_Auto TexToTexSampledAOPS();
    CullMode = None;        
  }
}

technique TextureToTextureResampledAO_3x3_First
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();            
    PixelShader = compile ps_Auto TexToTexSampledAOPS_3x3_First();
    CullMode = None;        
  }
}

technique TextureToTextureResampledAO_3x3_Second
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();            
    PixelShader = compile ps_Auto TexToTexSampledAOPS_3x3_Second();
    CullMode = None;        
  }
}

technique TextureToTexture
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();            
    PixelShader = compile ps_Auto TexToTexPS();
    CullMode = None;        
  }
}

technique TextureToTextureResampled
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();            
    PixelShader = compile ps_Auto TexToTexSampledPS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// AlphaTest Anti Aliasing technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

//pass rotated grid coords too
struct vtxOutAA
{
  float4 HPosition  : POSITION;
  float2 baseTC     : TEXCOORDN;
  float4 baseTCmY   : TEXCOORDN;  
  float4 baseTCpX   : TEXCOORDN;
  float4 baseTCpY   : TEXCOORDN;    
  float4 baseTCmX   : TEXCOORDN;      
  float4 RotatedGridX: TEXCOORDN;        
  float4 RotatedGridY: TEXCOORDN;          
};

struct vtxOutAAOpt
{
  float4 HPosition  : POSITION;
  float2 baseTC     : TEXCOORDN;
  float2 baseTC0    : TEXCOORDN;  
  float2 baseTC1    : TEXCOORDN;
  float2 baseTC2    : TEXCOORDN;
};

/// Constants ////////////////////////////


/// Samplers ////////////////////////////


///////////////// vertex shader //////////////////
vtxOutAA EdgeAAVS(vtxIn IN)
{
  vtxOutAA OUT = (vtxOutAA)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  half2 ddX = RotGridScreenOffset.xy;
  half2 ddY = RotGridScreenOffset.zw;  
 
  OUT.baseTCmY.xy = IN.baseTC.xy - ddY.xy;
  OUT.baseTCpX.xy = IN.baseTC.xy + ddX.xy;
  OUT.baseTCpY.xy = IN.baseTC.xy + ddY.xy;
  OUT.baseTCmX.xy = IN.baseTC.xy - ddX.xy;      


  OUT.RotatedGridX = 0.66 * float4(-ddY.x, ddX.x, ddY.x, -ddX.x);
  OUT.RotatedGridY = 0.66 * float4(-ddY.y, ddX.y, ddY.y, -ddX.y);  

  return OUT;
}

vtxOutAAOpt EdgeAAOptVS(vtxIn IN)
{
  vtxOutAAOpt OUT = (vtxOutAAOpt)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  // using a rotated triangle for sampling
  OUT.baseTC0.xy = IN.baseTC.xy - 2 * g_VS_ScreenSize.zw * (float2(-0.939, 0.342) + float2(0.342, -0.939));
  OUT.baseTC1.xy = IN.baseTC.xy + 2 * g_VS_ScreenSize.zw * float2(-0.939, 0.342);
  OUT.baseTC2.xy = IN.baseTC.xy +2 *g_VS_ScreenSize.zw * float2(0.342, -0.939);
 
  return OUT;
}

///////////////// pixel shader //////////////////
pixout EdgePS(vtxOutAA IN)
{
  pixout OUT;
  //edge aa 

#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif

  half4 samples;  
  
  //sample center, determines whether to blend and is reference value for depth comparison
  half2 sampleCenter	= tex2D(_tex1, IN.baseTC.xy).xy;    
  half dep = sampleCenter.x;	  

  half2 sampleUp	   = tex2D(_tex1, IN.baseTCmY.xy).xy;    
  half2 sampleRight = tex2D(_tex1, IN.baseTCpX.xy).xy;    
  half2 sampleDown  = tex2D(_tex1, IN.baseTCpY.xy).xy;    
  half2 sampleLeft  = tex2D(_tex1, IN.baseTCmX.xy).xy;    

	samples.x = dep - sampleUp.x;	  
  samples.y = dep - sampleRight.x;	  
  samples.z = dep - sampleDown.x;	  
  samples.w = dep - sampleLeft.x;	  
  half threshold = 0.016 * dep;
  
  samples.xyzw = (samples.xyzw>threshold);
  
  //these 2 lines would fade out the edhge AA in some distance
//	half minDep = min(sampleUp.x, min(sampleDown.x, min(sampleRight.x, sampleLeft.x)));
//	samples.xyzw *= (minDep < 0.045);
  
  half sum = dot(samples,1);  
  half2 texCoordOffset = half2(0,0);        


  half4 ddX = IN.RotatedGridX;
  half4 ddY = IN.RotatedGridY;  
  if(sum == 4)
    texCoordOffset = ddY.xy;//in case that all pixels are contributing to the texCoordOffset, assign some offset
  texCoordOffset.x += dot(samples, ddX);
  texCoordOffset.y += dot(samples, ddY);  
  
  OUT.Color = tex2D(_tex0, IN.baseTC.xy + texCoordOffset);  //perform dependent texture read with adjusted offset, zero for most pixel      

/*
//displays just the outlining
if(dot(samples,1) == 0)
OUT.Color = 0;
else 
OUT.Color = 1;  
*/

  return OUT;
}

///////////////// pixel shader //////////////////
pixout EdgePS2PixelBlurTest(vtxOutAA IN)
{
  pixout OUT;
  //edge aa
  half4 samples = 0;  
  half4 samples2 = 0;

#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif

  //sample center, determines whether to blend and is reference value for depth comparison
  half2 sampleCenter	= tex2D(_tex1, IN.baseTC.xy).xy;    
  half dep = sampleCenter.x;	  

  half2 sampleUp	   = tex2D(_tex1, IN.baseTCmY.xy).xy;    
  half2 sampleRight = tex2D(_tex1, IN.baseTCpX.xy).xy;    
  half2 sampleDown  = tex2D(_tex1, IN.baseTCpY.xy).xy;    
  half2 sampleLeft  = tex2D(_tex1, IN.baseTCmX.xy).xy;    

	samples.x = -dep + sampleUp.x;	  
	samples.y = -dep + sampleRight.x;	  
	samples.z = -dep + sampleDown.x;	  
	samples.w = -dep + sampleLeft.x;	  

	samples2.x = dep - sampleUp.x;	  
	samples2.y = dep - sampleRight.x;	  
	samples2.z = dep - sampleDown.x;	  
	samples2.w = dep - sampleLeft.x;	  

	half threshold = 0.03 * dep;
	
	samples2.xyzw = (samples2.xyzw>threshold);
		
  samples.xyzw = (samples.xyzw>threshold);	
	samples = saturate(samples + samples2);
//	half minDep = min(sampleUp.x, min(sampleDown.x, min(sampleRight.x, sampleLeft.x)));
//	samples.xyzw *= (minDep < 0.045);
  
  half sum = dot(samples,1);  
  half2 texCoordOffset = half2(0,0);        

	half4 colCenter = tex2D(_tex0, IN.baseTC.xy);
	half4 colUp	   = tex2D(_tex0, IN.baseTCmY.xy);
	half4 colRight  = tex2D(_tex0, IN.baseTCpX.xy);
	half4 colDown   = tex2D(_tex0, IN.baseTCpY.xy);
	half4 colLeft   = tex2D(_tex0, IN.baseTCmX.xy);
	half4 resCol		 = colCenter*2;
	resCol += colUp * samples.x;
	resCol += colRight * samples.y;
	resCol += colDown * samples.z;
	resCol += colLeft * samples.w;
	resCol *= 1.0 / (sum+2);
	OUT.Color.xyz = resCol.xyz;
	OUT.Color.w = colCenter.w;

/*
//displays just the outlining
if(dot(samples2,1) == 0)
OUT.Color = 0;
else 
OUT.Color = 1;  
*/
  return OUT;
}

// optimized edge blurring - using rotated triangle filter + dependend lookup instead of 4 extra lookups
pixout EdgePS2PixelBlurTestOpt(vtxOutAAOpt IN)
{
  pixout OUT;
  //edge aa
  half4 samples = 2;  
  half4 samples2 = 2;

#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif

  half sampleDepthUp	   = tex2D(_tex1, IN.baseTC0.xy).x;    
  half sampleDepthRight = tex2D(_tex1, IN.baseTC1.xy).x;    
  half sampleDepthDown  = tex2D(_tex1, IN.baseTC2.xy).x;    

  half sampleDepthCenter	= tex2D(_tex1, IN.baseTC.xy).x;; //(sampleDepthUp + sampleDepthRight + sampleDepthDown ) * 0.3333333;
  half dep = sampleDepthCenter.x;	  
  samples.xyz = float3(sampleDepthUp.x, sampleDepthRight.x, sampleDepthDown.x);
  samples.xyz -= dep;

  samples2.xyz = - float3( sampleDepthUp.x, sampleDepthRight.x, sampleDepthDown.x );	  
  samples2.xyz += dep;

	half threshold = 0.003 * dep;
	
	samples2.xyz = (samples2.xyz>threshold);		
  samples.xyz = (samples.xyz>threshold);	
	samples.xyz = saturate(samples.xyz + samples2.xyz);
  
  half fRecipSum = 1.0 / dot(samples,1);  
	
	half4 cSampleAvg = tex2D(_tex0, (IN.baseTC.xy*2 + 
	                                  IN.baseTC0.xy * samples.x +// + 
	                                  IN.baseTC1.xy * samples.y+ // + 
	                                  IN.baseTC2.xy * samples.z)*fRecipSum );
	                                            
	OUT.Color = cSampleAvg; 

  //OUT.Color = dot(samples.xyz, 0.333);
  
/*//displays just the outlining
if(dot(samples2.xyz,1) == 0)
OUT.Color = 0;
else 
OUT.Color = 1;  
*/
  return OUT;
}

////////////////// technique /////////////////////
technique EdgeAA
{
  pass p0
  {        
    CullMode = None;        
#ifdef PS30    
    VertexShader = compile vs_3_0 EdgeAAVS();
    PixelShader = compile ps_3_0 EdgePS();
#else    
    VertexShader = compile vs_2_0 EdgeAAVS();
    PixelShader = compile ps_2_0 EdgePS();
#endif    
  }
}

technique EdgeBlur
{
  pass p0
  {        
    CullMode = None;        
    VertexShader = compile vs_2_0 EdgeAAVS();
    PixelShader = compile ps_2_0 EdgePS2PixelBlurTest();    
  }
}

technique EdgeBlurOpt
{
  pass p0
  {        
    CullMode = None;        
    VertexShader = compile vs_2_0 EdgeAAOptVS();
    PixelShader = compile ps_2_0 EdgePS2PixelBlurTestOpt();    
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clear screen technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 clrScrParams;

/// Samplers ////////////////////////////
// none

///////////////// vertex shader //////////////////

struct vtxOutClrScr
{
  float4 HPosition  : POSITION;
};

vtxOutClrScr ClearScreenVS(vtxIn IN)
{
  vtxOutClrScr OUT = (vtxOutClrScr)0; 
  OUT.HPosition = mul(vpMatrix, IN.Position);    
  return OUT;
}

///////////////// pixel shader //////////////////
pixout ClearScreenPS(vtxOutClrScr IN)
{
  pixout OUT;  
  OUT.Color = clrScrParams;        
  return OUT;
}

////////////////// technique /////////////////////
technique ClearScreen
{
  pass p0
  {
    VertexShader = compile vs_Auto ClearScreenVS();
    PixelShader = compile ps_Auto ClearScreenPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Kawase Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 blurParams0;
float4 blurParams1;

/// Samplers ////////////////////////////

// none
sampler2D blurMap0 : register(s0);

///////////////// vertex shader //////////////////

struct vtxOutKawase
{
  float4 HPosition  : POSITION;
  float2 baseTC0 : TEXCOORDN;    
  float2 baseTC1 : TEXCOORDN;    
  float2 baseTC2 : TEXCOORDN;    
  float2 baseTC3 : TEXCOORDN;    
  float2 baseTC4 : TEXCOORDN;    
};

vtxOutKawase KawaseBlurVS(vtxIn IN)
{
  vtxOutKawase OUT = (vtxOutKawase)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC0.xy = IN.baseTC.xy; // Also sample midle pixel to keep some detail
  OUT.baseTC1.xy = IN.baseTC.xy+blurParams0.xy;
  OUT.baseTC2.xy = IN.baseTC.xy+blurParams0.zw;
  OUT.baseTC3.xy = IN.baseTC.xy+blurParams1.xy;
  OUT.baseTC4.xy = IN.baseTC.xy+blurParams1.zw;

  return OUT;
}

///////////////// pixel shader //////////////////
pixout KawaseBlurPS(vtxOutKawase IN)
{
  pixout OUT;
  
  half4 baseColor0 = tex2D(blurMap0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(blurMap0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(blurMap0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(blurMap0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(blurMap0, IN.baseTC4.xy);
  
  OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)/5.0;        
  
  return OUT;
}

////////////////// technique /////////////////////
technique KawaseBlur
{
  pass p0
  {
    VertexShader = compile vs_Auto KawaseBlurVS();
    PixelShader = compile ps_Auto KawaseBlurPS();
    
    CullMode = Back;        
  }
}

// =================================================================================================
// Technique: GaussBlur/GaussBlurBilinear
// Description: Applies a separatable vertical/horizontal gaussian blur filter
// =================================================================================================

float4 PI_psOffsets[16];
float4 psWeights[16];

struct vtxOutGauss
{
  float4 HPosition : POSITION;
  float4 tc0 : TEXCOORDN;    
  float4 tc1 : TEXCOORDN;    
  float2 tc2 : TEXCOORDN;    
  float2 tc3 : TEXCOORDN;    
  float2 tc4 : TEXCOORDN;    
  float2 tc5 : TEXCOORDN;      
  float2 tc6 : TEXCOORDN;    
  float2 tc7 : TEXCOORDN;    
};

vtxOutGauss GaussBlurBilinearVS(vtxIn IN)
{
  vtxOutGauss OUT = (vtxOutGauss) 0;

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.tc0.xy = IN.baseTC.xy + PI_psOffsets[0].xy;
  OUT.tc1.xy = IN.baseTC.xy + PI_psOffsets[1].xy;
  OUT.tc2.xy = IN.baseTC.xy + PI_psOffsets[2].xy;
  OUT.tc3.xy = IN.baseTC.xy + PI_psOffsets[3].xy;
  OUT.tc4.xy = IN.baseTC.xy + PI_psOffsets[4].xy;
  OUT.tc5.xy = IN.baseTC.xy + PI_psOffsets[5].xy;
  OUT.tc6.xy = IN.baseTC.xy + PI_psOffsets[6].xy;
  OUT.tc7.xy = IN.baseTC.xy + PI_psOffsets[7].xy;

  // special case for masked blur  - output with correct aspect ratio into wz
  OUT.tc0.wz = IN.baseTC.xy;
  OUT.tc1.wz = (IN.baseTC.xy -0.5 ) * float2(0.75*(ScrSize.x/ScrSize.y), 1.0) + 0.5;

  return OUT;
}

pixout GaussBlurBilinearPS(vtxOutGauss IN)
{
  pixout OUT;

  half4 sum = 0;
    
	half4 col = tex2D(_tex0, IN.tc0.xy) ;  	
	sum += col * (half) psWeights[0].x;  

	col = tex2D(_tex0, IN.tc1.xy) ;  
	sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy) ;  
	sum += col * (half) psWeights[2].x;  

	col = tex2D(_tex0, IN.tc3.xy) ;  
	sum += col * (half) psWeights[3].x;  

	col = tex2D(_tex0, IN.tc4.xy) ;  
	sum += col * (half) psWeights[4].x;  
	
	col = tex2D(_tex0, IN.tc5.xy) ;  
	sum += col * (half) psWeights[5].x;  
	
	col = tex2D(_tex0, IN.tc6.xy) ;  
	sum += col * (half) psWeights[6].x;  
	
	col = tex2D(_tex0, IN.tc7.xy) ;  
	sum += col * (half) psWeights[7].x;  

  OUT.Color = sum;
  return OUT;
}

pixout MaskedGaussBlurBilinearPS(vtxOutGauss IN)
{
  pixout OUT;

  half4 sum = 0;
  half4 orig = tex2D(_tex0, IN.tc0.wz) ;
  half mask = tex2D(_tex1, IN.tc1.wz).x ;
  
	half4 col = tex2D(_tex0, IN.tc0.xy) ;  	
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[0].x;  

	col = tex2D(_tex0, IN.tc1.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[2].x;  

	col = tex2D(_tex0, IN.tc3.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[3].x;  

	col = tex2D(_tex0, IN.tc4.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[4].x;  
	
	col = tex2D(_tex0, IN.tc5.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[5].x;  
	
	col = tex2D(_tex0, IN.tc6.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[6].x;  
	
	col = tex2D(_tex0, IN.tc7.xy) ;  
  col = lerp(orig, col, mask);
	sum += col * (half) psWeights[7].x;  

  OUT.Color = sum;
  return OUT;
}


pixout GaussBlurBilinearEncodedPS(vtxOutGauss IN)
{
  pixout OUT;
      
  half3 sum = 0;
  half3 col = DecodeRGBS( tex2D(_tex0, IN.tc0.xy) );  	
  sum += col * (half) psWeights[0].x;  

  col = DecodeRGBS( tex2D(_tex0, IN.tc1.xy) );  
  sum += col * (half) psWeights[1].x;  
	
  col = DecodeRGBS( tex2D(_tex0, IN.tc2.xy) );  
  sum += col * (half) psWeights[2].x;  

  col = DecodeRGBS(tex2D(_tex0, IN.tc3.xy) );  
  sum += col * (half) psWeights[3].x;  

  col = DecodeRGBS(tex2D(_tex0, IN.tc4.xy) );  
  sum += col * (half) psWeights[4].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc5.xy) );  
  sum += col * (half) psWeights[5].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc6.xy) );  
  sum += col * (half) psWeights[6].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc7.xy) );  
  sum += col * (half) psWeights[7].x;  

  OUT.Color = EncodeRGBS( float4( sum.xyz, 1) );
    
  return OUT;
}

pixout GaussBlurPS(vtxOut IN)
{
  pixout OUT;

  int samples = 16;
    
  half4 sum = 0;
  for(int i=0; i<samples; i++)
  {
	  half4 col = tex2D(_tex0, IN.baseTC.xy + PI_psOffsets[i].xy) ;  
	  sum += col * psWeights[i];  
  }  
        
  OUT.Color = sum;
  return OUT;
}

technique GaussBlur
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto GaussBlurPS();    
  }
}

// Optimized gauss blur version, making use of bilinear filtering
technique GaussBlurBilinear
{
  pass p0
  {
    VertexShader = compile vs_Auto GaussBlurBilinearVS();
    PixelShader = compile ps_Auto GaussBlurBilinearPS();    
  }
}

technique MaskedGaussBlurBilinear
{
  pass p0
  {
    VertexShader = compile vs_Auto GaussBlurBilinearVS();
    PixelShader = compile ps_Auto MaskedGaussBlurBilinearPS();    
  }
}


technique GaussBlurBilinearEncoded
{
  pass p0
  {
    VertexShader = compile vs_Auto GaussBlurBilinearVS();
    PixelShader = compile ps_Auto GaussBlurBilinearEncodedPS();    
  }
}


// ===================================================================================================
// Technique: GaussAlphaBlur
// Description: Applies a separatable vertical/horizontal gaussian blur filter for alpha channel only
// ===================================================================================================
// FIX:: oprimize
struct vtxOutAlphaBlur
{
  float4 HPosition : POSITION;
  float4 tc0 : TEXCOORDN;    
  float2 tc1 : TEXCOORDN;    
  float2 tc2 : TEXCOORDN;    
  float2 tc3 : TEXCOORDN;    
  float2 tc4 : TEXCOORDN;    
  float2 tc5 : TEXCOORDN;      
  float2 tc6 : TEXCOORDN;    
  float2 tc7 : TEXCOORDN;    
};

vtxOutAlphaBlur GaussAlphaBlurVS(vtxIn IN)
{
  vtxOutAlphaBlur OUT = (vtxOutAlphaBlur) 0;

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
	OUT.tc0.zw = IN.baseTC.xy;

  OUT.tc0.xy = IN.baseTC.xy + PI_psOffsets[0].xy;
  OUT.tc1.xy = IN.baseTC.xy + PI_psOffsets[1].xy;
  OUT.tc2.xy = IN.baseTC.xy + PI_psOffsets[2].xy;
  OUT.tc3.xy = IN.baseTC.xy + PI_psOffsets[3].xy;
  OUT.tc4.xy = IN.baseTC.xy + PI_psOffsets[4].xy;
  OUT.tc5.xy = IN.baseTC.xy + PI_psOffsets[5].xy;
  OUT.tc6.xy = IN.baseTC.xy + PI_psOffsets[6].xy;
  OUT.tc7.xy = IN.baseTC.xy + PI_psOffsets[7].xy;

  return OUT;
}

pixout GaussAlphaBlurPS(vtxOutAlphaBlur IN)
{
  pixout OUT;

  half sum = 0;
  
	half col = tex2D(_tex0, IN.tc0.xy).a ;  	
	sum += col * (half) psWeights[0].x;  

	col = tex2D(_tex0, IN.tc1.xy).a ;  
	sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy).a ;  
	sum += col * (half) psWeights[2].x;  

	col = tex2D(_tex0, IN.tc3.xy).a ;  
	sum += col * (half) psWeights[3].x;  

	col = tex2D(_tex0, IN.tc4.xy).a ;  
	sum += col * (half) psWeights[4].x;  
	
	col = tex2D(_tex0, IN.tc5.xy).a ;  
	sum += col * (half) psWeights[5].x;  
	
	col = tex2D(_tex0, IN.tc6.xy).a ;  
	sum += col * (half) psWeights[6].x;  
	
	col = tex2D(_tex0, IN.tc7.xy).a ;  
	sum += col * (half) psWeights[7].x;  

  OUT.Color.xyz = tex2D(_tex0, IN.tc0.zw).xyz; 
	OUT.Color.a = sum;
  return OUT;
}

technique GaussAlphaBlur
{
  pass p0
  {
    VertexShader = compile vs_Auto GaussAlphaBlurVS();
    PixelShader = compile ps_Auto GaussAlphaBlurPS();    
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Kawase Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

///////////////// vertex shader //////////////////

struct vtxOutAnisotropicVertical
{
  float4 HPosition  : POSITION;
  float2 baseTC0 : TEXCOORDN;    
  float2 baseTC1 : TEXCOORDN;    
  float2 baseTC2 : TEXCOORDN;    
  float2 baseTC3 : TEXCOORDN;    
  float2 baseTC4 : TEXCOORDN;    
  float2 baseTC5 : TEXCOORDN;    
  float2 baseTC6 : TEXCOORDN;    
  float2 baseTC7 : TEXCOORDN;    
};

vtxOutAnisotropicVertical AnisotropicVerticalVS(vtxIn IN)
{
  vtxOutAnisotropicVertical OUT = (vtxOutAnisotropicVertical)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
    
  OUT.baseTC0.xy = IN.baseTC.xy + float2(0,blurParams0.x)*0.125*0.75f;
  OUT.baseTC1.xy = IN.baseTC.xy + float2(0,blurParams0.y)*0.125*0.75f;
  OUT.baseTC2.xy = IN.baseTC.xy + float2(0,blurParams0.z)*0.125*0.75f;
  OUT.baseTC3.xy = IN.baseTC.xy + float2(0,blurParams0.w)*0.125*0.75f;

  OUT.baseTC4.xy = IN.baseTC.xy - float2(0,blurParams0.x)*0.75f;
  OUT.baseTC5.xy = IN.baseTC.xy - float2(0,blurParams0.y)*0.75f;
  OUT.baseTC6.xy = IN.baseTC.xy - float2(0,blurParams0.z)*0.75f;
  OUT.baseTC7.xy = IN.baseTC.xy - float2(0,blurParams0.w)*0.75f;

  return OUT;
}

///////////////// pixel shader //////////////////
pixout AnisotropicVerticalBlurPS(vtxOutAnisotropicVertical IN)
{
  pixout OUT;
  
  float4 canis = tex2D(blurMap0, IN.baseTC0.xy);
  canis += tex2D(blurMap0, IN.baseTC1.xy);
  canis += tex2D(blurMap0, IN.baseTC2.xy);
  canis += tex2D(blurMap0, IN.baseTC3.xy);
  canis += tex2D(blurMap0, IN.baseTC4.xy);
  canis += tex2D(blurMap0, IN.baseTC5.xy);
  canis += tex2D(blurMap0, IN.baseTC6.xy);
  canis += tex2D(blurMap0, IN.baseTC7.xy);
 

  OUT.Color = canis / 8.0;
  
  return OUT;
}

////////////////// technique /////////////////////
technique AnisotropicVertical
{
  pass p0
  {
    VertexShader = compile vs_Auto AnisotropicVerticalVS();
    PixelShader = compile ps_Auto AnisotropicVerticalBlurPS();
    
    CullMode = Back;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Dilate technique for sprites ///////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

float4 vPixelOffset;			// PS 1/width,1/height,?,?
float4 vDilateParams;			// PS brightness_multiplier,?,?,?

/// Constants ///////////////////////////

////////////////// samplers /////////////////////

///////////////// vertex shader //////////////////

struct vtxInDilate
{
  IN_P
  IN_TBASE
  IN_C0
};

struct vtxOutDilate
{
  float4 HPosition  : POSITION;
  float2 baseTC : TEXCOORD0;    
};

vtxOutDilate DilateVS(vtxInDilate IN)
{
  vtxOutDilate OUT = (vtxOutDilate)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);    
  OUT.baseTC.xy = IN.baseTC.xy;

	OUT.baseTC.xy+=0.00001f;		// lookup more in the middle of the texel - fixes white spots on DX10

  return OUT;
}


///////////////// pixel shader //////////////////
pixout DilatePS(vtxOutDilate IN)
{
  pixout OUT;

	const half2 Kernel_Neighbors[8+12] = 
	{
		-1.0f,0.0f,
		1.0f,0.0f,
		0.0f,-1.0f,
		0.0f,1.0f,

		-1.0f,-1.0f,
		-1.0f,1.0f,
		1.0f,-1.0f,
		1.0f,1.0f,

		-2.0f,0.0f,
		2.0f,0.0f,
		0.0f,-2.0f,
		0.0f,2.0f,

		-2.0f,1.0f,
		2.0f,1.0f,
		1.0f,-2.0f,
		1.0f,2.0f,

		-2.0f,-1.0f,
		2.0f,-1.0f,
		-1.0f,-2.0f,
		-1.0f,2.0f,
	};
/*
	// weighted - for fast dilation
	const float3 Kernel_WeightedNeighbors[13] = 
	{
		0.0f,0.0f,		256.0f*16.0f, 

		-1.0f,0.0f,		1.0f,	
		1.0f,0.0f,		1.0f,
		0.0f,-1.0f,		1.0f,
		0.0f,1.0f,		1.0f,

		-1.0f,-1.0f,	1.0f/64.0f,
		-1.0f,1.0f,		1.0f/64.0f,
		1.0f,-1.0f,		1.0f/64.0f,
		1.0f,1.0f,		1.0f/64.0f,

		-2.0f,0.0f,		1.0f/256.0f,
		2.0f,0.0f,		1.0f/256.0f,
		0.0f,-2.0f,		1.0f/256.0f,
		0.0f,2.0f,		1.0f/256.0f,
	};
*/

/*
	// fast dilation  
	float4 cSum = float4(0,0,0,0.001f);		//  0.001f to avoid division by zero

  for(int i=0;i<9+4;i++)
  {
		float4 val=tex2D(_tex0,IN.baseTC.xy+Kernel_WeightedNeighbors[i].xy*vPixelOffset.xy);
  
		cSum += float4(val.rgb,(val.a>0.05f)?1:0) * Kernel_WeightedNeighbors[i].z;
	}

	OUT.Color = float4(vDilateParams.x * cSum.rgb/cSum.a,tex2D(_tex0,IN.baseTC.xy).a);
*/

	float4 cBase0 = tex2D(_tex0, IN.baseTC.xy);		                  // sun contribution
	float4 cBase1 = tex2D(_tex0, IN.baseTC.xy + vPixelOffset.zw);		// sky contribution
	
	OUT.Color = cBase0;

	half4 cColor0 = cBase0;		// sun contribution

	float2 vBestOffset = IN.baseTC.xy;
	//half2 vBestOffset = half2(0,0);

#ifdef D3D10
  [unroll]
#endif

	int iSampleCount=8;

  if( GetShaderQuality() > QUALITY_LOW )
  	iSampleCount=8+12;

	for(int i=0;i<iSampleCount;i++)	
	{
		float2 vLocalOffset = IN.baseTC.xy+Kernel_Neighbors[i].xy*vPixelOffset.xy;
		half4 cVal0 = tex2D(_tex0, vLocalOffset);		// sun contribution
		
		if (cVal0.a > 0.0f)
		{
			cColor0 = cVal0;
			vBestOffset = vLocalOffset;
		}
	}
	
	half4 cColor1 = tex2D(_tex0, vBestOffset + vPixelOffset.zw);		// sky contribution

	OUT.Color = cColor0+cColor1;

	half fContribution = max(cColor0.r,max(cColor0.g,cColor0.b)) / max(OUT.Color.r,max(OUT.Color.g,OUT.Color.b));		// Sun/(Sun+Sky)
	
	OUT.Color *= vDilateParams.x;		// adjust HDR values to LDR range

  const half SpriteAlphaRef=0.1;

	OUT.Color.a = (cBase0.a>0.0f) ? 1.0f-fContribution*(1.0-SpriteAlphaRef) : 0;
	//OUT.Color.a = cBase0.a;
	//OUT.Color = cBase1; //.a*0.3; // * 0.4;
//  OUT.Color.a = 1;
  return OUT;
}

////////////////// technique /////////////////////

technique Dilate
{
  pass p0
  {
    VertexShader = compile vs_Auto DilateVS();            
    PixelShader = compile ps_Auto DilatePS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Color correction technique /////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 mColorMatrix;

///////////////// pixel shader //////////////////

pixout ColorCorrectionPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = half4(tex2D(_tex0, IN.baseTC.xy).xyz, 1);         
    
  // Apply color transformation matrix to ajust saturation/brightness/constrast
  screenColor.xyz=  float3( dot(screenColor.xyzw, mColorMatrix[0].xyzw),
						    dot(screenColor.xyzw, mColorMatrix[1].xyzw),
                            dot(screenColor.xyzw, mColorMatrix[2].xyzw) );
                         
  // Ajust image gamma                                    
  //screenColor.xyz=pow(screenColor.xyz, renderModeParamsPS.w);
    
  OUT.Color = screenColor;
    
  return OUT;
}

////////////////// technique /////////////////////

technique ColorCorrection
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto ColorCorrectionPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Image blurring techniques //////////////////////////////////////////////////////////////////////

///////////////// pixel shader //////////////////

pixout BlurInterpolationPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = tex2D( _tex0, IN.baseTC.xy );
  half4 blurredColor = tex2D( _tex1, IN.baseTC.xy );
    
  OUT.Color = lerp(blurredColor, screenColor, psParams[0].w);
    
  return OUT;
}

////////////////// technique /////////////////////

technique BlurInterpolation
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto BlurInterpolationPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Masked Image blurring techniques //////////////////////////////////////////////////////////////////////

///////////////// pixel shader //////////////////

pixout MaskedBlurInterpolationPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = tex2D( _tex0, IN.baseTC.xy );
  half4 blurredColor = tex2D( _tex1, IN.baseTC.xy );
  half mask = tex2D( _tex2, IN.baseTC.wz ).x;
  mask = sqrt( mask );
    
  OUT.Color = lerp(blurredColor, screenColor, mask * psParams[0].w);
    
  return OUT;
}

////////////////// technique /////////////////////

technique MaskedBlurInterpolation
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto MaskedBlurInterpolationPS();    
    CullMode = None;        
  }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
/// Radial blurring technique //////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

// xy = radial center screen space position, z = radius attenuation, w = blur strenght
float4 vRadialBlurParams;

///////////////// pixel shader //////////////////

pixout RadialBlurringPS(vtxOut IN)
{
  pixout OUT;
  
  float2 vScreenPos = vRadialBlurParams.xy;
  
  float2 vBlurVec = ( vScreenPos.xy - IN.baseTC.xy);
  
  float fInvRadius = vRadialBlurParams.z;
  float blurDist = saturate( 1- dot( vBlurVec.xy * fInvRadius, vBlurVec.xy * fInvRadius)) ;
  vRadialBlurParams.w *= blurDist*blurDist;
  
  const int nSamples = 8; 
  const float fWeight = 1.0 / (float) nSamples;
  
  half4 cAccum = 0;   
  for(int i=0; i < nSamples; i++)
  {
    half4 cCurr = tex2D(_tex0, (IN.baseTC.xy + vBlurVec.xy * i * vRadialBlurParams.w) );      
    cAccum += cCurr;// * (1.0-i * fWeight);
  }
    
  OUT.Color = cAccum * fWeight;
      
  return OUT;
}
////////////////// technique /////////////////////

technique RadialBlurring
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto RadialBlurringPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// AlphaTest Anti Aliasing technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

//pass rotated grid coords too
struct vtxOutAA
{
  float4 HPosition  : POSITION;
  float2 baseTC     : TEXCOORDN;
  float4 baseTCmY   : TEXCOORDN;  
  float4 baseTCpX   : TEXCOORDN;
  float4 baseTCpY   : TEXCOORDN;    
  float4 baseTCmX   : TEXCOORDN;      
  float4 RotatedGridX: TEXCOORDN;        
  float4 RotatedGridY: TEXCOORDN;          
};

/// Constants ////////////////////////////


/// Samplers ////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Motion Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

struct vtxOutMotionBlurDispl
{
  float4 HPosition  : POSITION;
  float4 tcProj     : TEXCOORDN;
  float4 vVelocity  : TEXCOORDN;
  float4 vVelocityPrev  : TEXCOORDN;
};

/// Constants ////////////////////////////


float4 PI_motionBlurParams;

float4 motionBlurParams;
float4 motionBlurChromaParams;
float4 motionBlurCamParams;
float4x4 mViewProjPrev;
float4 vDirectionalBlur;;

/// Samplers ////////////////////////////

sampler2D motionBlurMaskMap : register(s1);

///////////////// vertex shaders //////////////////

vtxOutMotionBlurDispl MotionBlurDisplVS(vtxIn IN)
{
  vtxOutMotionBlurDispl OUT = (vtxOutMotionBlurDispl)0; 

  float4 vPos = IN.Position;
  vPos.xyz = normalize(vPos.xyz) * 25; // * motionBlurCamParams.w; // sphere size needs to be tweakable for setting blur strenght
  vPos.xyz += g_VS_WorldViewPos.xyz;
  
  OUT.HPosition = mul(vpMatrix, vPos);  
      
  float4 vNewPos = OUT.HPosition;
  float4 vPrevPos =  mul(mViewProjPrev, vPos);
  
  OUT.vVelocity =  HPosToScreenTC( vNewPos );
  OUT.vVelocityPrev = HPosToScreenTC( vPrevPos );  

  OUT.tcProj = HPosToScreenTC( OUT.HPosition );

  return OUT;
}

///////////////// pixel shaders //////////////////

pixout MotionBlurdDepthMaskPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float fDepth = tex2D(depthMapSampler, IN.baseTC).x;
  half mask_accum = exp(-fDepth* 25);
    //saturate( 1 - fDepth* 20.0 ); // 1 alu
  mask_accum *= mask_accum; //^2                // 1 alu 
  //mask_accum *= mask_accum; //^4               // 1 alu
  //mask_accum *= mask_accum; //^8               // 1 alu


  float fRotationAmount = (motionBlurParams.w * 5.0);

  half fNearestMask = ( fDepth * PS_NearFarClipDist.y );  // 1 alu
  fNearestMask = saturate( fNearestMask - 1.0 )*saturate(mask_accum + fRotationAmount);       // 2 alu
  //tcFinal +=  vVelocityLerp.xy * (s - s * fNearestMask);							// 2 alu

  OUT.Color.xyz = tex2D(screenMapSampler, IN.baseTC);
  OUT.Color.w = fNearestMask;//fNearestMask; // store mask in screen map alpha

  return OUT;
}

pixout MotionBlurDepthMaskHDRPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

#if D3D10
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC);
  OUT.Color += tex2D(_tex1, IN.baseTC);
#endif

  float fDepth = tex2D(_tex1, IN.baseTC).x;
  half mask_accum = exp(-fDepth* 25);
    //saturate( 1 - fDepth* 20.0 ); // 1 alu
  mask_accum *= mask_accum; //^2                // 1 alu 
  //mask_accum *= mask_accum; //^4               // 1 alu
  //mask_accum *= mask_accum; //^8               // 1 alu


  float fRotationAmount = (motionBlurParams.w * 5.0);

  half fNearestMask = ( fDepth * PS_NearFarClipDist.y );  // 1 alu
  fNearestMask = saturate( fNearestMask - 1.0 )*saturate(mask_accum + fRotationAmount);       // 2 alu
  //tcFinal +=  vVelocityLerp.xy * (s - s * fNearestMask);							// 2 alu

  OUT.Color.xyz = tex2D(_tex0, IN.baseTC);
  OUT.Color.w = fNearestMask;//fNearestMask; // store mask in screen map alpha

  return OUT;
}

float2 GetVelocity( sampler2D sVelocity, float2 tc )
{
  float4 cVelocity = tex2Dlod(sVelocity, float4(tc.xy, 0, 0));
  float fDecodedLenght = cVelocity.z; //dot(cVelocity.zw, float2( 255.0 * 255.0 , 255.0 ) );

  return cVelocity.xy; //(cVelocity.xy*2-1) * fDecodedLenght;
}

pixout MotionBlurObjectPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;

	float2 poisson[8] = {  
	  float2( 0.0,      0.0),
    float2( 0.527837,-0.085868),
	  float2(-0.040088, 0.536087),
	  float2(-0.670445,-0.179949),
	  float2(-0.419418,-0.616039),
	  float2( 0.440453,-0.639399),
	  float2(-0.757088, 0.349334),
	  float2( 0.574619, 0.685879)
	};
	
  float4 cOrig = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0));
  float4 cDummyFetchDx10 = tex2Dlod(_tex1, float4(IN.baseTC.xy, 0, 0)); // dummy fetch for dx10 samplers order declaration workaround
  float fOrigDepth = tex2Dlod(_tex2, float4(IN.baseTC.xy, 0, 0)).x;

  /*OUT.Color.xy = cOrig.xy*0.001 + GetVelocity(_tex1, IN.baseTC.xy);
  OUT.Color.wz = 0;

  return OUT;
*/
  float4 Blurred = 0;  
  float2 pixelVelocity;
  
  int NumberOfPostProcessSamples = 8;           
  int nSamples = 8;
  float fUseAllSamples = 0;

  //bool bSingleSample = true;

  //{
  //  for(int n= 0; n<nSamples; n++)
  //  {	    
  //    float2 vOffset = poisson[n]* 0.0333;  // this must scale depending on camera distance
  //    // Sample neightboord pixels velocity
  //    float4 curFramePixelVelocity = tex2Dlod(_tex0, float4(OriginalUV + vOffset, 0, 0));
	 // 	if( !dot(curFramePixelVelocity, 1) )
  //    {
  //      fUseAllSamples = 1;
  //      break;
  //    }
  //  }
  //}

  int s= 0;

#if D3D10
  [unroll]
#endif
  for(int n= 0; n<nSamples; n++)
  {	    
    // todo: this must scale depending on camera distance or object size on screen
    float2 vOffset = poisson[n]* 0.0333 * saturate((1-fOrigDepth)*(1-fOrigDepth) );
    float  fCurrDepth = tex2Dlod(_tex2, float4(OriginalUV + vOffset, 0, 0)).x;
    if ( fCurrDepth > fOrigDepth )
      continue;

    // Sample neightboord pixels velocity
    float2 curFramePixelVelocity = GetVelocity(_tex1, OriginalUV + vOffset);
    pixelVelocity.xy =  curFramePixelVelocity;
        
    half fLen = dot(pixelVelocity.xy,pixelVelocity.xy);
		if( fLen )
		{	           
#if D3D10
  [unroll]
#endif
	    for(float i = 0; i < NumberOfPostProcessSamples; i++)
	    {   
	    	float2 lookup = pixelVelocity * ((i / NumberOfPostProcessSamples)-0.5) * PI_motionBlurParams.x + OriginalUV;
	      	      
	      // Lookup color/velocity at this new spot
	      float4 Current = tex2Dlod(_tex0, float4(lookup.xy, 0, 0));
	    	float4 curVelocity = tex2Dlod(_tex1, float4(lookup.xy, 0, 0));
	    	half fBlend = ( length(curVelocity)); 
	    	//float2 curVelocity = GetVelocity(_tex1, lookup.xy);
	    	//float fBlend = length(curVelocity); 
	    		    		      
	      Blurred.xyz += Current;
	      Blurred.w  += fBlend;	      
	      s++;
	    }            
    }

//    if( !fUseAllSamples )
  //    break;
  }

  OUT.Color = float4( cOrig.xyz, 1);
  if( s )
  {
    // Return the average color of all the samples
    float fLerp = Blurred.w/(float)s;     
    OUT.Color.xyz =float4(lerp(cOrig.xyz, Blurred.xyz/(float)s, saturate(fLerp*3)), 1);
  }

  return OUT;
}

pixout MotionBlurObjectNoDilationPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  
  
  float4 OriginalUV = IN.baseTC;

	float2 poisson[8] = {  
	  float2( 0.0,      0.0),
	  float2( 0.527837,-0.085868),
	  float2(-0.040088, 0.536087),
	  float2(-0.670445,-0.179949),
	  float2(-0.419418,-0.616039),
	  float2( 0.440453,-0.639399),
	  float2(-0.757088, 0.349334),
	  float2( 0.574619, 0.685879)
	};
		
  float4 vVelocities = tex2D(_tex0, OriginalUV);
  float4 cOrig = tex2D(_tex1, OriginalUV);
  float fDepthOrig = tex2D(_tex2, OriginalUV).x* PS_NearFarClipDist.y;
  
	float4 Blurred = 0;  
  float2 pixelVelocity;
  int NumberOfPostProcessSamples = 8;
            
  int nSamples = 8;
  float nDivSamples = 1.0 / (float) nSamples;
  
  int s= 0;
  int n = 0;
//  for(int n= 0; n<nSamples; n++)
  {	    
    //float fOffset = n * nDivSamples* 2.0 -1.0;
    float2 vOffset = poisson[n]* 0.0333;  // this must scale depending on camera distance
    
    // Sample neightboord pixels velocity
    float4 curFramePixelVelocity = tex2Dlod(_tex0, float4(OriginalUV + vOffset, 0, 0));
    //curFramePixelVelocity.xy -= curFramePixelVelocity.zw;

		float4 curColor = tex2Dlod(_tex1, float4(OriginalUV + vOffset, 0, 0));

    pixelVelocity.x =  curFramePixelVelocity.r;// * PixelBlurConst;   
    pixelVelocity.y = curFramePixelVelocity.g;// * PixelBlurConst;    

/*    OUT.Color = 0;
    OUT.Color.xy = pixelVelocity.xy;
    return OUT;
  */      
    float fLen = dot(pixelVelocity.xy, pixelVelocity.xy);
		if( fLen )
		{	     
#if D3D10
  [unroll]
#endif
	    for(int i=0; i<NumberOfPostProcessSamples; i++)
	    {   
	    	//float fAtten =  abs((i / (float)NumberOfPostProcessSamples)*2-1);
	    	//float fAtten = 1-saturate( length(pixelVelocity *((i / NumberOfPostProcessSamples)-0.5)) *100 );
	    	
	    	float2 lookup = pixelVelocity * ((i / NumberOfPostProcessSamples)-0.5) + OriginalUV;
	    	
	    	float4 curVelocity = tex2Dlod(_tex0, float4(lookup.xy, 0, 0));
	    	
	    	float fIDCurr = curVelocity.w;//tex2Dlod(_tex0, float4(lookup.xy, 0, 0)).w;
	    	
	    	//float fDepthCurr = tex2Dlod(_tex2, float4(lookup.xy, 0, 0)).x* PS_NearFarClipDist.y;	    	
	    	float fMasking = curFramePixelVelocity.w == fIDCurr;
	    	
	    	float fBlend = fMasking*( length(curVelocity));
	    		    	
	      lookup = pixelVelocity * ((i / NumberOfPostProcessSamples)-0.5) + OriginalUV;
	      
	      // Lookup the color at this new spot
	      float4 Current = tex2Dlod(_tex1, float4(lookup.xy, 0, 0));
	                     
	      // Accumulate blured velocity and remove pixels withouth velocity
	      //Blurred.xyz += lerp(0, Current.rgb,  fLen )*fAtten;
	      //Blurred.xyz += lerp(cOrig,  Current.rgb, saturate(4*fAtten))*fAtten;
	          	      
	      Blurred.xyz += Current;//lerp(cOrig,Current,saturate(fBlend*32));//*max(fMasking, 0.5);//, fMasking);
	      Blurred.w  += fBlend; //max(fMasking, 0.5);
	      
	      s++;
	    }            
    }
  }
    
  // Return the average color of all the samples
  float fLerp = Blurred.w/(float)s;     
  OUT.Color = float4(lerp(cOrig, Blurred.xyz/(float)s, saturate(fLerp*3)), 1);

  return OUT;
}

pixout MotionBlurDisplPS(vtxOutMotionBlurDispl IN)
{  
  pixout OUT = (pixout)0;  

  int nQuality = GetShaderQuality();

  float fSamples = 8.0;

  const float fWeight = (1.0 / fSamples);  
  const float fWeightStep = (2.0 / fSamples);
  
  //motionBlurParams.w = 1.5;

  float2 vVelocityPrev = ( (IN.vVelocityPrev.xy/IN.vVelocityPrev.w))* PI_motionBlurParams.w;	// 1 div, 1 mul
  
  float2 vVelocity = (IN.vVelocity.xy/IN.vVelocity.w);									// 1 div
  float2 vVelocityDiv = vVelocity;
  vVelocity *= PI_motionBlurParams.w;

  float2 vVelocityLerp = vVelocityPrev - vVelocity;										// 1 sub							

  vVelocityDiv.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
  vVelocityLerp.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
      
  float4 accum = 0;

  half4 cMidCurr = tex2Dproj(screenMapSampler, IN.tcProj.xyzw);  

#if D3D10
  [unroll]
#endif
  for(float s = -1.0; s < 1.0 ; s += fWeightStep )										// 1 add
  {																						
	  float2 tcFinal =  vVelocityDiv.xy - vVelocityLerp.xy * s;							// 1 alu
    
    if( nQuality == QUALITY_HIGH )
    {
      half fDepthMask = tex2D(screenMapSampler, tcFinal).w;
      tcFinal +=  vVelocityLerp.xy * (s - s * fDepthMask);							// 2 alu
    }

    accum += tex2D(screenMapSampler, tcFinal ); // 1 alu
  }
  
  accum *= fWeight;                                                                                 // 1 alu
   
  // Remove scene bleeding from 1st player hands
  half fDepth = tex2Dproj(depthMapSampler, IN.tcProj.xyzw).x * PS_NearFarClipDist.y;               // 1 alu
  OUT.Color = lerp(cMidCurr, accum, saturate(fDepth-1.0) );                                        // 3 alu //fDepth*100; //
  //OUT.Color.w =1;
  
  return OUT;
}

pixout MotionBlurDisplHDRPS(vtxOutMotionBlurDispl IN)
{  
  pixout OUT = (pixout)0;  

  int nQuality = GetShaderQuality();

  half fSamples = 8.0;

  const half fWeight = (1.0 / fSamples);  
  const half fWeightStep = (2.0 / fSamples);
  
  //motionBlurParams.w = 1.5;

  half2 vVelocityPrev = ( (IN.vVelocityPrev.xy/IN.vVelocityPrev.w))* PI_motionBlurParams.w;	// 1 div, 1 mul
  
  half2 vVelocity = (IN.vVelocity.xy/IN.vVelocity.w);									// 1 div
  half2 vVelocityDiv = vVelocity;
  vVelocity *= PI_motionBlurParams.w;

  half2 vVelocityLerp = vVelocityPrev - vVelocity;										// 1 sub							

  vVelocityDiv.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
  vVelocityLerp.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
      
  half4 accum = 0;

  half4 cMidCurr = tex2Dproj(screenTargetSampler, IN.tcProj.xyzw);  

#if D3D10
  [unroll]
#endif
  for(half s = -1.0; s < 1.0 ; s += fWeightStep )										// 1 add
  {																						
	  half2 tcFinal =  vVelocityDiv.xy - vVelocityLerp.xy * s;							// 1 alu
    
    half fDepthMask = tex2D(screenTargetSampler, tcFinal).w;
    tcFinal +=  vVelocityLerp.xy * (s - s * fDepthMask);							// 2 alu

    accum += tex2D(screenTargetSampler, tcFinal );; // 1 alu
  }
  
  accum *= fWeight;                                                                                 // 1 alu
   
  // Remove scene bleeding from 1st player hands
  half fDepth = tex2Dproj(depthMapSampler, IN.tcProj.xyzw).x * PS_NearFarClipDist.y;               // 1 alu
  OUT.Color = lerp(cMidCurr, accum, saturate(fDepth-1.0) );                                        // 3 alu //fDepth*100; //
  //OUT.Color.w =1;
  
  return OUT;
}

////////////////// technique /////////////////////

technique MotionBlurMaskGen
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto MotionBlurdDepthMaskPS();
    CullMode = None;        
  }
}

technique MotionBlurMaskGenHDR
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto MotionBlurDepthMaskHDRPS();
    CullMode = None;        
  }
}

technique MotionBlurDispl
{
  pass p0
  {
    VertexShader = compile vs_Auto MotionBlurDisplVS();
    PixelShader = compile ps_Auto MotionBlurDisplPS();
    CullMode = None;        
  }
}

technique MotionBlurDisplHDR
{
  pass p0
  {
    VertexShader = compile vs_Auto MotionBlurDisplVS();
    PixelShader = compile ps_Auto MotionBlurDisplHDRPS();
    CullMode = None;        
  }
}

#if %DYN_BRANCHING_POSTPROCESS

technique MotionBlurObjectNoDilation
{
  pass p0
  {
    VertexShader = compile vs_3_0 BaseVS();
    PixelShader = compile ps_3_0 MotionBlurObjectNoDilationPS();
    CullMode = None;  
  }
}

technique MotionBlurObject
{
  pass p0
  {
    VertexShader = compile vs_3_0 BaseVS();
    PixelShader = compile ps_3_0 MotionBlurObjectPS();
    CullMode = None;      
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Depth of field technique ///////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 dofParamsFocus;
float4 dofParamsBlur;
float4 pixelSizes;
float radiusScale = 0.8; //0.4;
float dofMinThreshold = 0.8;//0.5; // to ensure a smoother transition between near focus plane and focused area

/// Samplers /////////////////////////////

///////////////// vertex shader //////////////////

///////////////// pixel shader //////////////////
half GetDepthBlurinessBiased(half fDepth)
{
  half f=0; 

  // 0 - in focus
  // 1 or -1 - completely out of focus
    
  if(fDepth>(half)dofParamsFocus.y)
  {
    f=(fDepth-(half)dofParamsFocus.y)/(half)dofParamsFocus.z; // max range
    f=clamp(f, 0, 1-(half)dofMinThreshold);       
  }
  else
  if(fDepth<=(half)dofParamsFocus.x)
  {
    //f=1;//((half)dofParamsFocus.x-fDepth)/(half)dofParamsFocus.w;  // min range
    
    f=(1-fDepth/dofParamsFocus.x)/dofParamsFocus.w;  // min range
    
    //f=clamp(f, 0, 1-dofMinThreshold);   // make sure there's a diference blur between max range and min range
  }
  
  return f;
}

pixout CopyDepthToAlphaBiasedNoMaskPS(vtxOut IN)
{
  pixout OUT;  
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif
    
  half4 depthMap = tex2D(_tex0, IN.baseTC.xy);        	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = (GetDepthBlurinessBiased(depthNormalized))*dofParamsFocus.w;	  
    
#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex1, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;


  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );
#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

pixout CopyDepthToAlphaBiasedPS(vtxOut IN)
{
  pixout OUT;  
  
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif

  half depthMaskColor = tex2D(_tex1, IN.baseTC.xy).x;  
    
  half4 depthMap = tex2D(_tex0, IN.baseTC.xy);        	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = (GetDepthBlurinessBiased(depthNormalized) * depthMaskColor)*dofParamsFocus.w;	  

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex2, IN.baseTC.xy).xyz, 0);


  //cScreen = max( min( cScreen, (float3)10000000 ), 0 );
  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;


  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

half GetDepthBluriness(half fDepth)
{  
  half f=fDepth-(half)dofParamsFocus.z;
 
  // 0 - in focus
  // 1 or -1 - completely out of focus
    
  if(fDepth<(half)dofParamsFocus.z)
  {
    f/=(half)dofParamsFocus.x;      
  }
  else
  {
    f/=dofParamsFocus.y;         
    f=clamp(f, 0, 1-(half)dofMinThreshold);   
  }    
  
  return f;
}

pixout CopyDepthToAlphaNoMaskPS(vtxOut IN)
{
  pixout OUT;  
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif
    
  half4 depthMap = tex2D(_tex0, IN.baseTC.xy);        	
  half depthNormalized = depthMap.x*PS_NearFarClipDist.y;	  
  half depth = saturate(GetDepthBluriness(depthNormalized))*dofParamsFocus.w;	  

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex1, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;


  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

pixout CopyDepthToAlphaPS(vtxOut IN)
{
  pixout OUT;  
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif

  half depthMaskColor = tex2D(_tex1, IN.baseTC.xy).x; 
  
  half4 depthMap = tex2D(_tex0, IN.baseTC.xy);        	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = saturate((GetDepthBluriness(depthNormalized))*depthMaskColor + depthMaskColor)*dofParamsFocus.w;

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex2, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;

  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}
	
pixout DofHDRPS(vtxOut IN)
{
  pixout OUT;

  int nQuality = GetShaderQuality();

const int tapCount = 141;
  float2 poisson[141] =
  {
      



        1.797,    -0.352,  
        1.871,    -0.130,  
        1.875,     0.104,  
        1.810,     0.328,  
        1.693,     0.532,  
        1.575,     0.736,  
        1.458,     0.939,  
        1.340,     1.143,  
        1.223,     1.346,  
        1.078,     1.530,  
        0.883,     1.659,  
        1.556,     0.324,  
       -1.611,     0.052,  
        1.378,    -0.555,  
        1.338,     0.507,  
        1.338,     0.170,  
        1.338,    -0.167,  
        1.613,     0.003,  
       -0.963,     1.616,  
       -1.142,     1.465,  
       -1.268,     1.268,  
       -1.386,     1.064,  
       -1.503,     0.861,  
       -1.621,     0.657,  
       -1.738,     0.454,  
       -1.844,     0.245,  
       -1.881,     0.013,  
       -1.852,    -0.219,  
       -1.751,    -0.430,  
       -1.634,    -0.634,  
       -1.517,    -0.837,  
       -1.399,    -1.041,  
       -1.282,    -1.244,  
       -1.159,    -1.445,  
       -0.985,    -1.601,  
       -1.137,    -0.671,  
       -1.217,     0.003,  
       -1.137,     0.339,  
       -1.137,     0.676,  
       -1.137,     1.013,  
       -1.137,    -0.334,  
       -1.129,    -0.999,  
       -1.422,     0.279,  
        1.058,    -1.547,  
        1.209,    -1.369,  
        1.327,    -1.166,  
        1.444,    -0.962,  
        1.562,    -0.759,  
        1.679,    -0.555,  
        1.797,    -0.352,  
        0.840,     1.306,  
        0.794,     0.854,  
        0.789,     0.506,  
        0.789,     0.170,  
        0.789,    -0.167,  
        0.789,    -0.504,  
        0.789,    -0.840,  
        0.789,    -1.177,  
        0.789,    -1.514,  
        1.064,    -0.334,  
        1.064,     1.013,  
        1.121,     0.727,  
        1.064,     0.339,  
        1.064,     0.002,  
        1.098,    -1.028,  
        1.109,    -0.698,  
        0.238,     0.170,  
        0.238,     1.180,  
        0.238,     0.843,  
        0.238,     0.506,  
        0.238,    -1.177,  
        0.238,    -0.167,  
        0.238,    -0.504,  
        0.238,    -0.840,  
        0.238,     1.517,  
        0.238,    -1.514,  
        0.513,    -0.334,  
        0.541,     1.045,  
        0.513,     0.676,  
        0.513,     0.339,  
        0.513,     0.002,  
        0.513,    -1.008,  
        0.513,    -0.671,  
        0.513,    -1.344,  
        0.548,     1.371,  
       -0.312,     0.170,  
       -0.312,     1.180,  
       -0.312,     0.843,  
       -0.312,     0.506,  
       -0.312,    -1.177,  
       -0.312,    -0.167,  
       -0.312,    -0.504,  
       -0.312,    -0.840,  
       -0.312,     1.517,  
       -0.312,    -1.514,  
       -0.037,    -0.334,  
       -0.037,     1.013,  
       -0.037,     0.676,  
       -0.037,     0.339,  
       -0.037,     0.002,  
       -0.037,    -1.008,  
       -0.037,    -0.671,  
       -0.037,    -1.344,  
       -0.037,     1.349,  
       -0.863,     0.170,  
       -0.896,     1.229,  
       -0.863,     0.843,  
       -0.863,     0.506,  
       -0.863,    -1.177,  
       -0.863,    -0.167,  
       -0.863,    -0.504,  
       -0.863,    -0.840,  
       -0.827,    -1.425,  
       -0.588,    -0.334,  
       -0.588,     1.013,  
       -0.588,     0.676,  
       -0.588,     0.339,  
       -0.588,     0.002,  
       -0.588,    -1.008,  
       -0.588,    -0.671,  
       -0.588,    -1.344,  
       -0.593,     1.411,  
       -1.412,    -0.504,  
       -1.388,     0.541,  
       -1.480,    -0.230,  
        1.549,    -0.296,  
        0.633,    -1.731,  
        0.398,    -1.732,  
        0.163,    -1.732,  
       -0.072,    -1.732,  
       -0.307,    -1.732,  
       -0.542,    -1.732,  
       -0.774,    -1.702,  
       -0.748,     1.710,  
       -0.515,     1.732,  
       -0.280,     1.732,  
       -0.045,     1.732,  
        0.190,     1.732,  
        0.425,     1.732,  
        0.659,     1.728,  
        0.859,    -1.670,  






  };
  
  float4 cOut=0;
  half discRadius;
  half discRadiusLow;
  half centerDepth;
  half centerDepthLow;
        
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy) + tex2D(_tex1, IN.baseTC.xy)*0.5;
#endif
        
  float2 vNoiseTC = IN.baseTC.xy * PS_ScreenSize.xy/64.0;
  float2 vNoise = tex2D(_tex2, vNoiseTC)+ dot(IN.baseTC.xy, 1) * 65535;
  vNoise = frac( vNoise );

  vNoise = vNoise*2-1;
  vNoise *= 0.05;
  //vNoise = 0;
  //OUT.Color =vNoise.xyxy;
  //return OUT;

  //float2 voff = vNoise * pixelSizes.zw; //poisson[frac(length(IN.baseTC.xy))*7]
  //IN.baseTC.xy += voff;//vNoise*0.01;

  // fetch center tap from blured low res image
  centerDepth = tex2D(_tex1, IN.baseTC.xy + vNoise * pixelSizes.zw).w;    
  //centerDepthLow = tex2D(_tex1, IN.baseTC.xy).w;    

  //OUT.Color = abs(centerDepth*2-1); //*2-1>0;
  //return OUT;
  
  //IN.baseTC.xy -= voff;//vNoise*0.01;

  discRadius=(centerDepth*(half)dofParamsBlur.y-(half)dofParamsBlur.x);
  discRadiusLow=discRadius*(half)radiusScale;
  
  float2 texsize_hi = pixelSizes.xy*discRadius;
  //float2 texsize_med = pixelSizes.xy * 0.5 * discRadius;
  float2 texsize_low = pixelSizes.zw * discRadiusLow;

  //pixelSizes.xy=(half2)pixelSizes.xy*discRadius;
  //pixelSizes.wz=(half2)pixelSizes.zw*discRadiusLow;

  //vNoise = 0;
//  vNoise.xy *=2;

//  OUT.Color = tex2D(_tex1, IN.baseTC.xy);    
//  OUT.Color = vNoise;
//  return OUT;
//  float4 tapMed = tex2D(_tex2, IN.baseTC.xy);
  //OUT.Color = tapMed;
  //return OUT;

#if D3D10
  [unroll]
#endif
  for(int t=0; t<tapCount; t++)
  { 
    float4 tapHigh=tex2Dlod(_tex0, float4(IN.baseTC.xy+ (poisson[t] + saturate(t)*vNoise)*texsize_hi, 0, 0));
    //float4 tapMed=tex2Dlod(_tex1, float4(IN.baseTC.xy+ (poisson[t] + saturate(t)*vNoise)*texsize_med, 0, 0));
    float4 tapLow=tex2Dlod(_tex1, float4(IN.baseTC.xy+ (poisson[t] + saturate(t)*vNoise)*texsize_low, 0, 0));
    

   // if( tapHigh.a > 0.5)
    {
      //tapHigh.a = abs( tapHigh.a*2-1  );
      //tapLow.a = abs( tapLow.a*2-1  );
      //centerDepth = abs( centerDepth *2-1 );

      half tapLerp=saturate( tapHigh.a*2-1);;        
//      half4 tap=lerp(tapMed, tapLow, saturate( max(tapLerp, 0.5)*2-1 ) );    
      half4 tap=lerp(tapHigh, tapLow, tapLerp);

  //    tap=lerp(tapHigh, tap, min(tapLerp, 0.5)*2);    
      tap.a=(tapLow.a - centerDepth + dofMinThreshold > 0.0)? 1.0 : saturate(tap.a*2-1);    

      cOut.xyz += tap.a*tap.xyz;
      cOut.w += tap.a;
    }
    /*else
    {
      tapHigh.a = abs( tapHigh.a*2-1  );
      tapLow.a = abs( tapLow.a*2-1  );
*/
/*
      half tapLerp=((tapHigh.a)*2.0-1.0);        
      half4 tap=lerp(tapHigh, tapLow, saturate(tapLerp));    
      tap.a=(tapLow.a - centerDepthLow + 0.001 > 0.0)? 1.0 : saturate(tap.a*2.0-1.0);    

      cOut.xyz += tap.a*tap.xyz;
      cOut.w += tap.a;*/
/*
      half tapLerp=((tapLow.a)*2.0-1.0);        
      cOut.xyz += lerp(tapHigh, tapLow, tapLerp);
      cOut.w+= 1;

    }
  */    
    /*
    half tapLerp=((tapHigh.a)*2.0-1.0);        
    half4 tap=lerp(tapHigh, tapLow, saturate(tapLerp));    
    
    // Apply leak reduction. Make sure only to reduce on focused areas            
    //tap.a=(tapLow.a-centerDepth+tapLerp*dot(vNoise.xy, 1)>0.001)? saturate(tapHigh.a*2.0-1.0): saturate(tapLow.a*2.0-1.0);    
    
    /////tap.a=(tapLow.a-centerDepth+tapLerp*dot(vNoise.xy, 1)>0.001)? 1: saturate(tapLow.a*2.0-1.0);    

    tap.a=(tapLow.a-centerDepth+saturate(tap.a*2-1)*dot(vNoise.xy, 1)+  0.001>0.0)? saturate(tap.a*2.0-1.0): saturate(tapLow.a*2.0-1.0);    
    //tap.a= (tapLow.a-centerDepth>0.001)? 1: tap.a;    
        
    //cOut.xyz+=tap.a*tap.xyz;
    cOut.xyz+=lerp(tapHigh, tapLow, saturate(tap.a));
    cOut.w+= 1;//tap.a;
    */
  }
                            
  OUT.Color = cOut/cOut.w;
  return OUT;
}

pixout DofPS(vtxOut IN)
{
  pixout OUT;

  int nQuality = GetShaderQuality();

#ifndef PS20Only    
  const int tapCount = (nQuality == QUALITY_HIGH) ? 8 : 4;

  float2 poisson[8] =
  {
       0.0,    0.0,
     0.527, -0.085,
    -0.040,  0.536,
    -0.670, -0.179,
    -0.419, -0.616,
     0.440, -0.639,
    -0.757,  0.349,
     0.574,  0.685,
  };

  if (nQuality == QUALITY_LOW)
  {
    poisson[0] = float2(0.527, -0.085);
    poisson[1] = float2(-0.040,  0.536);
    poisson[2] = float2(-0.419, -0.616);
    poisson[3] = float2(0.440, -0.639);
  }
 
#else
  const int tapCount=4;
  
  float2 poisson[4] =
  {
     0.527, -0.085,
    -0.040,  0.536,
    -0.419, -0.616,
     0.440, -0.639,
  };
    
#endif
  
  half4 cOut=0;
  half discRadius;
  half discRadiusLow;
  half centerDepth;
        
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif
        
  // fetch center tap from blured low res image
  centerDepth=tex2D(_tex1, IN.baseTC.xy).w;    

  discRadius=(centerDepth*(half)dofParamsBlur.y-(half)dofParamsBlur.x);
  discRadiusLow=discRadius*(half)radiusScale;
  
  pixelSizes.xy=(half2)pixelSizes.xy*discRadius;
  pixelSizes.wz=(half2)pixelSizes.zw*discRadiusLow;

#if D3D10
  [unroll]
#endif
  for(int t=0; t<tapCount; t++)
  { 
    half4 tapHigh=tex2D(_tex0, IN.baseTC.xy+ poisson[t]*(half2)pixelSizes.xy);                
    half4 tapLow=tex2D(_tex1, IN.baseTC.xy+ poisson[t]*(half2)pixelSizes.wz);        
        
    half tapLerp=(tapHigh.a*2.0-1.0);        
    half4 tap=lerp(tapHigh, tapLow, saturate(tapLerp));    
    
    // Apply leak reduction. Make sure only to reduce on focused areas            
    tap.a=(tapLow.a-centerDepth+(half)dofMinThreshold>0.0)? 1: saturate(tap.a*2.0-1.0);    
        
    cOut.xyz+=tap.a*tap.xyz;
    cOut.w+=tap.a;
  }
                            
  OUT.Color = cOut/cOut.w;
  return OUT;
}

////////////////// technique /////////////////////

technique CopyDepthToAlphaNoMask
{
  pass p0
  {        
    CullMode = None;        

         
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto CopyDepthToAlphaNoMaskPS();    
  }
}

technique CopyDepthToAlphaBiasedNoMask
{
  pass p0
  {        
    CullMode = None;        
            
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto CopyDepthToAlphaBiasedNoMaskPS();    

  }
}

technique CopyDepthToAlpha
{
  pass p0
  {        
    CullMode = None;        

    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto CopyDepthToAlphaPS();    

  }
}

technique CopyDepthToAlphaBiased
{
  pass p0
  {        
    CullMode = None;        
            
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto CopyDepthToAlphaBiasedPS();    

  }
}

technique DepthOfField
{
  pass p0
  {        
    CullMode = None;        
    
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto DofPS();    
  }
}

#if %DYN_BRANCHING_POSTPROCESS

technique DepthOfFieldHDR
{
  pass p0
  {        
    CullMode = None;        
    
    VertexShader = compile vs_3_0 BaseVS();
    PixelShader = compile ps_3_0 DofHDRPS();    
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Perspective Warp      //////////////////////////////////////////////////////////////////////////

struct a2v_perspectiveWarp
{
  float4 pos : POSITION;
};

struct v2f_perspectiveWarp
{
  float4 pos : POSITION;
  float2 tex : TEXCOORDN;
};

v2f_perspectiveWarp PerspectiveWarpVS( a2v_perspectiveWarp IN )
{
  v2f_perspectiveWarp OUT = (v2f_perspectiveWarp) 0; 

	const float pi = 3.141592;

	//float aspectRatio = 1022.0 / 683.0;
	//float aspectRatio = g_VS_ScreenSize.x / g_VS_ScreenSize.y;
	float aspectRatio = 1.3333;

  float normFovX = 60.0;
  float normFovY = normFovX / aspectRatio;	
	
  //float newFovX = 110.0;
  float newFovX = 90.0;
  float newFovY = newFovX / aspectRatio;  

  float scaleX = 1.0- ( normFovX / newFovX ); 
  float scaleY = 1.0 - ( normFovY / newFovY ); 

  float ratioX = ( newFovX / normFovX ) / pi;
  float ratioY = ( newFovY / normFovY ) / pi;  

	float2 normalizedPos = IN.pos.xy;		
	normalizedPos.y = -normalizedPos.y;	

	float angX = normalizedPos.x * newFovX * 0.5;
  float angY = normalizedPos.y * newFovY * 0.5;
  
  float2 warpedPos;
  warpedPos.x = ratioX * asin( scaleX * normalizedPos.x );
  warpedPos.y = ratioY * asin( scaleY * normalizedPos.y );   
  
  warpedPos.x /= cos( angX * pi / 180.0 );
  warpedPos.y /= cos( angY * pi / 180.0 );

  //warpedPos.x += sin( scaleX * normalizedPos.x );                
  //warpedPos.y += sin( scaleY * normalizedPos.y );           

  warpedPos.x += (1.0-scaleX) * sin( angX * pi / 180.0 );                
  warpedPos.y += (1.0-scaleY) * sin( angY * pi / 180.0 );           

  OUT.pos = float4( IN.pos.xy, 0, 1 );        
  OUT.tex = warpedPos * 0.5 + 0.5;        
 
/*
	float finalFOV = 60.0;
	float currentFOV = 110.0;
	
	float fovRatio =  ( currentFOV / finalFOV ) / 3.141592;
		
  OUT.pos = IN.pos ;        
  OUT.pos.zw = float2( 0, 1 );            

	float2 normalizedPos = IN.pos.xy;		
	normalizedPos.y = -normalizedPos.y;	
	
	float t = ( currentFOV / finalFOV ) / 2.0; 

  //OUT.tex.x = normalizedPos.x; 
  //OUT.tex.y = normalizedPos.y; 
	OUT.tex.x = fovRatio * asin( t * normalizedPos.x );	
	OUT.tex.y = fovRatio * asin( t * normalizedPos.y );			
	
	OUT.tex.xy = OUT.tex.xy * 0.5 + 0.5;		
*/

  return OUT;
}

pixout PerspectiveWarpPS( v2f_perspectiveWarp IN )
{
  pixout OUT;
  
	OUT.Color = tex2D( screenMapSampler, IN.tex.xy );			
	
  return OUT;
}

technique PerspectiveWarp
{
  pass p0
  {
    VertexShader = compile vs_Auto PerspectiveWarpVS();       
    PixelShader = compile ps_Auto PerspectiveWarpPS();
    CullMode = None;
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Glittering techniques//////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 glitterParams;
float4 glitterSprParams;

float4 camUpVector;
float4 camRightVector;

/// Samplers ////////////////////////////

sampler2D glitterScaledMap_d2 : register(s1);
sampler2D glitterScaledMap_d4 : register(s2);

sampler2D glitterSpriteSampler = sampler_state
{
  Texture = textures/defaults/glitter_sprite.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Clamp;
  AddressV = Clamp;
};

///////////////// vertex shader //////////////////

struct vtxInGlitterSprite
{
  IN_P    
  float3 baseTC : TEXCOORDN;
};

struct vtxOutGlitterSprite
{
  float4 HPosition  : POSITION;
  float3 baseTC     : TEXCOORDN;
  float4 glitCol    : TEXCOORDN;
  float4 screenPos  : TEXCOORDN;
};

///////////////// vertex shader //////////////////

vtxOutGlitterSprite glitterSpriteVS(vtxInGlitterSprite IN)
{

  vtxOutGlitterSprite OUT = (vtxOutGlitterSprite)0; 

  float4 vPos = float4(IN.Position.xyz, 1.0);
  
  // Get view vector  
  float3 viewVec = (vPos.xyz-g_VS_WorldViewPos.xyz);  
  
  // Compute sprite size
  float fDistToCam=length(viewVec);    
  float fSize=(fDistToCam/220.0)*clamp(glitterParams.w, 0.0, 2.0);  // 220.0f -> value tweaked by hand by MK...
        
  // Compute vertex coordinates based on camera right/up vector and texture coordinates
  float2 scale = fSize*2.0*(IN.baseTC.xy - 0.5);    
  
  vPos.z+=fSize*1.25; // try not to intersect with terrain
  vPos.xyz+=(camRightVector.xyz*scale.x + camUpVector.xyz*scale.y);
    
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = float2(IN.baseTC.x, 1-IN.baseTC.y);

  // Generate a normal based on position
  float3 normalVec = normalize(frac(IN.Position.xyz*100.0)*2.0-1.0);      
  
  // Compute attenuation term
  float attenDist=sqrt(IN.baseTC.z);    
  float fAttenuation=saturate(1.0-fDistToCam/attenDist);
     
  // Compute view dependency
  float3 camDir=normalize(-vpMatrix[2].xyz);
  float NdotV=dot(normalVec.xyz, camDir.xyz);
  
  // Compute glint term:
  // - 1. use fractional part of distance to camera
  // - 2. modulate absolute result by visibility term powered by some factor 
  float glintTerm=abs(frac((attenDist-fDistToCam)*0.5*glitterParams.x)*2-1)*saturate(4*pow(NdotV*0.5+0.5, glitterParams.y));
    
  // Final term is glint*distance attenuation
  OUT.glitCol.xyz= fAttenuation*glintTerm;
  
  // Cull sprite (todo: check performance gains, if any at all)
  if(OUT.glitCol.z<0.01)
  {
    OUT.HPosition=0;  
  }
    
  OUT.glitCol.w= NdotV;
  OUT.baseTC.z = fAttenuation;
  
  // Output screen space position for alpha masking
  OUT.screenPos = HPosToScreenTC(OUT.HPosition);
    
  return OUT;
}

///////////////// pixel shader //////////////////

// Used for glitter particles
pixout glitterSpritePS(vtxOutGlitterSprite IN)
{
  pixout OUT;
  half4 baseColor = tex2D(glitterSpriteSampler, IN.baseTC.xy);      
  half  screenAlphaColor = pow(tex2D(screenMapSampler, IN.screenPos.xy/IN.screenPos.ww).w, 16);
  
  half4  screenColor = tex2D(screenMapSampler, IN.baseTC.xy);

  // Fake chromatic Aberration  
  half4 chromAb = IN.glitCol+IN.glitCol*tex2D(rainbowSampler, IN.glitCol.ww);
  
  half3 final=chromAb.xyz*baseColor.xyz;
  // mask out alpha stuff
  OUT.Color.xyz=final.xyz;//*screenAlphaColor;
  
  half lum= dot(final.xyz, half3(0.33, 0.59, 0.11));
  OUT.Color.w= lum;
  
  return OUT;
}

// Glitering final pass (used if glitterGlare on)
pixout glitteringPassPS(vtxOut IN)
{
  pixout OUT;
  half4 baseColor = tex2D(_tex0, IN.baseTC.xy);      
    
  half4 glitterColor_d2 = tex2D(glitterScaledMap_d2, IN.baseTC.xy);      
  half4 glitterColor_d4 = tex2D(glitterScaledMap_d4, IN.baseTC.xy);        
  
  baseColor.xyz+=glitterColor_d2.w*glitterColor_d2.xyz*(1-baseColor.xyz)*2.0;    
  baseColor.xyz+=glitterColor_d4.w*glitterColor_d4.xyz*(1-baseColor.xyz)*2.0;    
  OUT.Color=baseColor;
  
  return OUT;
}

////////////////// technique /////////////////////

technique GlitterSprites
{
  pass p0
  {
    VertexShader = compile vs_Auto glitterSpriteVS();
    PixelShader = compile ps_Auto glitterSpritePS();      
    
    CullMode = None;   
    SrcBlend = ONE;
    DestBlend = ONE;
    AlphaBlendEnable = true;
    ZWriteEnable = false;
  }
}

technique GlitteringPass
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto glitteringPassPS();      
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Glow technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 glowParamsPS;

/// Samplers ////////////////////////////

sampler2D glowMap_RT1 : register(s1);
sampler2D glowMap_RT2 : register(s2);
sampler2D glowMap_RT3 : register(s3);

struct vtxInGlow
{
  IN_P
  IN_TBASE
  float3 CamVec    : TEXCOORD1;  
};

struct vtxOutGlow
{
  float4 HPosition  : POSITION; 
  float2 baseTC       : TEXCOORD0;
  float3 CamVec       : TEXCOORD1;  
};

vtxOutGlow GlowGenVS(vtxInGlow IN)
{
  vtxOutGlow OUT = (vtxOutGlow)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.CamVec.xyz = IN.CamVec.xyz;

  return OUT;
}

///////////////// pixel shader //////////////////

pixout SceneLuminancePassPS(vtxOut IN)
{
  pixout OUT;
  
  half4 tex_screen = tex2D( _tex0, IN.baseTC.xy );
  
  half fLum = saturate( dot(tex_screen.xyz, float3(0.33, 0.59, 0.11))  ) ;
  
  OUT.Color = half4(fLum.xxx, 0.02);
  
  return OUT;
}

pixout GlowBrightPassPS(vtxOut IN)
{
  pixout OUT;
  
  half4 tex_screen = tex2D(_tex0, IN.baseTC.xy);
  half4 tex_glow = tex2D(_tex1, IN.baseTC.xy);
  half4 tex_eyeadjust = tex2D(_tex2, IN.baseTC.xy);
  
  tex_screen = max(tex_screen - glowParamsPS.z, 0.0)/(tex_screen+glowParamsPS.z);
  tex_screen *= (1 - tex_eyeadjust) * glowParamsPS.w;
  //tex_screen *= (1 - tex_eyeadjust);
  
  //OUT.Color = tex_screen;//1 - exp( - ( tex_screen  + tex_glow ) );
  OUT.Color =  ( tex_screen  + tex_glow )  ;
  
  return OUT;
}


pixout GlowDisplayPS(vtxOut IN)
{
  pixout OUT;
  
  half4 tex_screen =tex2D(_tex0, IN.baseTC.xy);
  half4 tex_glow1 = tex2D(_tex1, IN.baseTC.xy);
  half4 tex_glow2 = tex2D(_tex2, IN.baseTC.xy);
  half4 tex_glow3 = tex2D(_tex3, IN.baseTC.xy);
  
  // Sum up results    
  half4 final_glow = (tex_glow1 + tex_glow2 + tex_glow3)* glowParamsPS.w;
    
  OUT.Color =final_glow+ tex_screen; //+ final_glow; //*(1-tex_screen) ; 
  return OUT;
}

////////////////// technique /////////////////////

technique SceneLuminancePass
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto SceneLuminancePassPS();    
    CullMode = None;        
  }
}

technique GlowBrightPass
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto GlowBrightPassPS();    
    CullMode = None;        
  }
}

technique GlowDisplay
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto GlowDisplayPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// GlowScene: copies glow into backbuffer /////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

////////////////// samplers /////////////////////

pixout GlowScenePS(vtxOut IN)
{
  pixout OUT;
  
  half4 cGlow = tex2D(_tex0, IN.baseTC.xy);
  OUT.Color.xyz = saturate(cGlow.xyz * cGlow.w);
  OUT.Color.w = dot( OUT.Color.xyz, 0.333);
  
  return OUT;
}

////////////////// technique /////////////////////
technique GlowScene
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();            
    PixelShader = compile ps_Auto GlowScenePS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// EncodeHDRGlow: encodes HDR glow into LDR glow texture //////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

////////////////// samplers /////////////////////

pixout EncodeHDRtoLDRPS(vtxOut IN)
{
  pixout OUT;
  
  OUT.Color = EncodeRGBS( tex2D( _tex0, IN.baseTC.xy) );
  
  return OUT;
}

////////////////// technique /////////////////////
technique EncodeHDRtoLDR
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();            
    PixelShader = compile ps_Auto EncodeHDRtoLDRPS();
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// SunShafts technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 PI_sunShaftsParams;
float4 sunShaftsParams;
float4x4 SunShafts_ViewProj;
float4 SunShafts_SunPos;

struct vtxOutSunShaftsGen
{
  float4 HPosition  : POSITION; 
  float2 baseTC       : TEXCOORD0;
  float4 sunPos       : TEXCOORD1;  
};

/// Samplers ////////////////////////////

vtxOutSunShaftsGen SunShaftsGenVS(vtxIn IN)
{
  vtxOutSunShaftsGen OUT = (vtxOutSunShaftsGen)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  float4 SunPosH = mul(SunShafts_ViewProj, SunShafts_SunPos);
  OUT.sunPos.x = (SunPosH.x + SunPosH.w) * 0.5 ;
  OUT.sunPos.y = (-SunPosH.y + SunPosH.w) * 0.5 ;
  OUT.sunPos.z = SunPosH.w;
  
  OUT.sunPos.w = (dot(normalize(SunShafts_SunPos).xyz, SunShafts_ViewProj[2].xyz));

  return OUT;
}

///////////////// pixel shader //////////////////

pixout SunShaftsMaskGenPS(vtxOutTexToTex IN)
{
  pixout OUT;
  
  int nQuality = GetShaderQuality();
  
  half4 scene = 0;
  half sceneDepth = 0;
  if( nQuality == QUALITY_HIGH )
  {
    half sceneDepth0 = tex2D(_tex0, IN.baseTC0.xy).r;
    half sceneDepth1 = tex2D(_tex0, IN.baseTC1.xy).r;
    half sceneDepth2 = tex2D(_tex0, IN.baseTC2.xy).r;
    half sceneDepth3 = tex2D(_tex0, IN.baseTC3.xy).r;
    half sceneDepth4 = tex2D(_tex0, IN.baseTC4.xy).r;    
    sceneDepth = (sceneDepth0 + sceneDepth1 + sceneDepth2 + sceneDepth3 + sceneDepth4) * 0.2;
    
    half4 scene0 = tex2D(_tex1, IN.baseTC0.xy);
    half4 scene1 = tex2D(_tex1, IN.baseTC1.xy);
    half4 scene2 = tex2D(_tex1, IN.baseTC2.xy);
    half4 scene3 = tex2D(_tex1, IN.baseTC3.xy);
    half4 scene4 = tex2D(_tex1, IN.baseTC4.xy);
    scene = (scene0 + scene1 + scene2 + scene3 + scene4) * 0.2;
  }
  else
  {
    sceneDepth = tex2D(_tex0, IN.baseTC0.xy).r;
    scene = tex2D(_tex1, IN.baseTC0.xy);
  }

  //half fMask = saturate( 8*(1-abs(sceneDepth*2-1)) ); 
  ///half fCloudsMask = 1 - saturate(tex2D(_tex1, IN.baseTC.xy).w*2-1);  
  half fShaftsMask = (1 - sceneDepth); //*fCloudsMask;  
  
  OUT.Color = half4( scene.xyz * saturate(sceneDepth), fShaftsMask );
    
  return OUT;
}

pixout SunShaftsGenPS(vtxOutSunShaftsGen IN)
{
  pixout OUT;
  
  float2 sunPosProj = ((IN.sunPos.xy / IN.sunPos.z));
  
  float fSign = (IN.sunPos.w);
  
  float2 sunVec = ( sunPosProj.xy - IN.baseTC.xy);
  
  float fAspectRatio =  1.333 * PS_ScreenSize.y /PS_ScreenSize.x;
  
  float sunDist = saturate(fSign) * saturate( 1 - saturate(length(sunVec * float2(1, fAspectRatio))*PI_sunShaftsParams.y));// * 
                            //saturate(saturate(fSign)*0.6+0.4  ) );
                            // *(1.0 - 0.2*(1- sin(AnimGenParams) ) pass variation per constant
  float2 sunDir =  ( sunPosProj.xy - IN.baseTC.xy);
   
  
  half4 accum = 0; 
  sunDir.xy *= PI_sunShaftsParams.x * fSign;
  
#if D3D10
  [unroll]
#endif
  for(int i=0; i<8; i++)
  {
    half4 depth = tex2D(_tex0, (IN.baseTC.xy + sunDir.xy * i) );      
    accum += depth * (1.0-i/8.0);
  }
  
  accum /= 8.0;

  OUT.Color = accum * 2  * float4(sunDist.xxx, 1);
  OUT.Color.w += 1-saturate(saturate(fSign*0.1+0.9));
  //OUT.Color.xyz *=1- saturate(0.5-0.5* fSign);
    
  return OUT;
}

//todo: add usefull blend modes into shade lib
float4 blendSoftLight(float4 a, float4 b)
{
  float4 c = 2 * a * b + a * a * (1 - 2 * b);
  float4 d = sqrt(a) * (2 * b - 1) + 2 * a * (1 - b);
  
  return ( b < 0.5 )? c : d;
}

pixout SunShaftsDisplayPS(vtxOut IN)
{
  pixout OUT;

  half4 cScreen = tex2D(_tex0, IN.baseTC.xy);      
  half4 cSunShafts = tex2D(_tex1, IN.baseTC.xy);

  half fShaftsMask = saturate(1.00001- cSunShafts.w) *sunShaftsParams.x * 2.0;
        
  // Apply "very" subtle (but always visible) sun shafts mask 
  float fBlend = cSunShafts.w;
  
  // normalize sun color (dont wanna huge values in here)
  float4 sunColor = 1;
  sunColor.xyz = normalize(g_PS_SunColor.xyz);
  
  // 
  OUT.Color =  cScreen + cSunShafts.xyzz * sunShaftsParams.y * sunColor * ( 1 - cScreen );
  OUT.Color = blendSoftLight(OUT.Color, sunColor * fShaftsMask *0.5+0.5);
   
  return OUT;
}

////////////////// technique /////////////////////

technique SunShaftsMaskGen
{
  pass p0
  {
    VertexShader = compile vs_Auto TexToTexVS();
    PixelShader = compile ps_Auto SunShaftsMaskGenPS();    
    CullMode = None;        
  }
}

technique SunShaftsGen
{
  pass p0
  {
    VertexShader = compile vs_Auto SunShaftsGenVS();
    PixelShader = compile ps_Auto SunShaftsGenPS();    
    CullMode = None;        
  }
}

technique SunShaftsDisplay
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto SunShaftsDisplayPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Depth Enhancement technique ////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4 vDepthEnhancementParams;

///////////////// pixel shader //////////////////

pixout DepthEnhancementPS(vtxOut IN)
{
  pixout OUT;
      
  half4 cScreen = tex2D(_tex0, IN.baseTC.xy );      
  
  float2 vSamples[8] =
  {
    -float2(0, 1),
    -float2(1, 0),
    float2(0, 1),
    float2(1, 0),
    
    float2(0.5, 0.85),
    float2(0.85, 0.5),
    -float2(0.5, 0.85),
    -float2(0.85, 0.5),
  };
  
  float fDepth = tex2D(_tex1, IN.baseTC.xy ).x * PS_NearFarClipDist.y;  
  
  
  float fDepthBlur = 0;
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 * vSamples[0] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[1] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[2] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[3] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 * vSamples[4] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[5] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[6] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - tex2D(_tex1, IN.baseTC.xy + 2 *vSamples[7] / ScrSize.xy).x*PS_NearFarClipDist.y ), 1.0) , -1.0) ;    
  
  fDepthBlur /= 8.0;
  
  fDepth *= PS_NearFarClipDist.y;
  //fDepthBlur *= PS_NearFarClipDist.y;    
  
  //OUT.Color = lerp(0.5, cScreen, max( 1-abs( fDepthLow - fDepth + 0.01)), 0) ); //1 - cScreen;
  
  //OUT.Color = lerp(0.5, cScreen,  1 + 0.5 * saturate( 100 * max( abs( fDepthLow - fDepth), 0) ));
  //OUT.Color =  cScreen * (1 - abs(fDepthBlur)*0.5);//lerp(dot(cScreen, float4(0.33, 0.59, 0.11, 0)), cScreen, 1.0 - fDepthBlur ); //max( min( ( fDepth - fDepthBlur ), 1.0) , -1.0) ;
  
  //OUT.Color =  lerp(0.5, cScreen, 1 + min( abs(fDepthBlur), 1.5) ); //max( min( ( fDepth - fDepthBlur ), 1.0) , -1.0) ;  
    
  OUT.Color = saturate(1- abs(fDepthBlur) )* cScreen;
  //OUT.Color = cScreen;
  
  //saturate( max( abs( fDepth - fDepthLow), 0) ); //saturate(fDepthLow > fDepth + 1.0 );
      
  return OUT;
}

////////////////// technique /////////////////////

technique DepthEnhancement
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto DepthEnhancementPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Chroma Shift technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

///////////////// pixel shader //////////////////

pixout ChromaShiftPS(vtxOut IN)
{
  pixout OUT;
      
  half4 cScreen = 0;
  
  cScreen.x = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].x) + 0.5).x;      
  cScreen.y = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].y) + 0.5).y;      
  cScreen.z = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].z) + 0.5).z;      
    
  OUT.Color = cScreen;

  return OUT;
}

////////////////// technique /////////////////////

technique ChromaShift
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto ChromaShiftPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// UnderwaterView technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

sampler2D underwaterBumpSampler = sampler_state
{
  Texture = textures/defaults/screen_noisy_bump.dds;
  MinFilter = LINEAR;  
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
};

///////////////// pixel shader //////////////////

pixout UnderwaterViewPS(vtxOut IN)
{
  pixout OUT;
    
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(screenMapSampler, IN.baseTC.xy);
#endif

  float anim = frac(AnimGenParams*0.01);  
  float3 vec = normalize(float3(IN.baseTC.xy *2-1, 1));
  half4 cBumpy = tex2D(underwaterBumpSampler, IN.baseTC.xy*0.025 + anim )*2-1;
  cBumpy += tex2D(underwaterBumpSampler, IN.baseTC.yx*0.033 - anim )*2-1;
  cBumpy.xyz = normalize( cBumpy ).xyz;
      
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy + cBumpy.xy*0.01);
  
  OUT.Color = cScreen;

  return OUT;
}

////////////////// technique /////////////////////

technique UnderwaterView
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto UnderwaterViewPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// UnderwaterGodRays technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 vpGodMatrix  : PI_Composite; // View*Projection
float4x4 vpGodMatrixI : PB_UnProjMatrix; // invert( View * projection )

float4 CausticsAmbient  : PI_Ambient;
float4 CausticParams	  : PB_CausticsParams;  // xy: caustics distance, zw: 1 / caustics distance


float4 PI_GodRaysParamsVS;
float4 PI_GodRaysParamsPS;
float4 PI_GodRaysSunDirVS;
float4 CausticSmoothSunDir	: PB_CausticsSmoothSunDirection; 


sampler2D wavesSampler = sampler_state
{
  Texture = textures/defaults/oceanwaves_ddn.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR;
  AddressU = Wrap;
  AddressV = Wrap;	
};

sampler2D causticsSampler = sampler_state
{
  Texture = textures/defaults/caustics_sampler.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = NONE;
  AddressU = Clamp;
  AddressV = Clamp;	
};

float g_fWaterLevel
<
  Position;
> = {PB_WaterLevel};

struct vtxOutGodRays
{
  float4 HPosition  : POSITION; 
  float4 baseTC    : TEXCOORDN; // zw unused
  
  float4 waveTC      : TEXCOORDN;
  float4 causticTC0  : TEXCOORDN;
  float4 causticTC1  : TEXCOORDN;
  
  float4 vPosition : TEXCOORDN;  // w unused   
};

/// Samplers ////////////////////////////

vtxOutGodRays UnderwaterGodRaysVS(vtxIn IN)
{
  vtxOutGodRays OUT = (vtxOutGodRays)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy *2 - 1);
  
  vPos.xy *= 1.2; // hack: make sure to cover entire screen
  
  // Increase each slice distance
  vPos.z = 0.1+ 0.88 * saturate(PI_GodRaysParamsVS.z * PI_GodRaysParamsVS.w);
  //vPos.z = 0.4+ 0. * saturate(vsParams[0].z * vsParams[0].w);
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(vpGodMatrixI, vPos );
  vPos /= vPos.w;
 
  OUT.HPosition = mul(vpGodMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.baseTC.y =  1 - OUT.baseTC.y;

  OUT.vPosition.xyz = vPos;
  OUT.vPosition.w = 1;
    
  // Generate projection matrix based on sun direction  
  float3 dirZ = CausticSmoothSunDir.xyz;
  float3 up = float3(0,0,1);
  float3 dirX = normalize(cross(up, dirZ));
  float3 dirY = normalize(cross(dirZ, dirX));

  float3x3 mLightView;
  mLightView[0] = dirX.xyz;
  mLightView[1] = dirY.xyz;
  mLightView[2] = dirZ.xyz;
   
  // Output caustics procedural texture generation 
  float2 uv = mul(mLightView, OUT.vPosition.xyz).xy*0.5;
  
  // half tilling used to avoid annoying aliasing when swimming fast
  OUT.waveTC.xy =  uv * 2 * 0.01 * 0.012 + g_VS_AnimGenParams.w * 0.06;
  OUT.waveTC.wz =  uv * 2 * 0.01 * 0.01 + g_VS_AnimGenParams.w * 0.05;

  OUT.causticTC0.xy =  uv * 0.01 * 0.5 *2+ g_VS_AnimGenParams.w * 0.1;
  OUT.causticTC0.wz =  uv.yx * 0.01 * 0.5 *2- g_VS_AnimGenParams.w * 0.11;  

  OUT.causticTC1.xy =  uv * 0.01 * 2.0 *2+ g_VS_AnimGenParams.w * 0.1;
  OUT.causticTC1.wz =  uv.yx * 0.01 * 2.0 *2- g_VS_AnimGenParams.w * 0.11;  

  return OUT;
}

///////////////// pixel shader //////////////////

pixout UnderwaterGodRaysPS(vtxOutGodRays IN)
{
  pixout OUT;
    
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(screenMapSampler, IN.baseTC.xy);
#endif
      
  // break movement, with random patterns
  float3 wave = 0;
  wave.xy = FetchNormalMap( wavesSampler, IN.waveTC.xy).xy;                                                  // 1 tex
  wave.xy += FetchNormalMap( wavesSampler, IN.waveTC.wz).xy;                                                 // 1 tex, 1 alu

  // Normalization optimization:
  //  - Instead of using GetNormalMap everywhere, which costs 3 alu per lookup, merge both
  //  bumps together, do single normalize after  
  
  // fast normalize
  wave.xy = wave.xy - 1.0;                                                                          // 1 alu
  wave.z = sqrt(1.0 - dot(wave.xy, wave.xy));                                                       // 2 alu    

  wave *= 0.02;                                                                                     // 1 alu  

  half3 causticMapR = 0;
  causticMapR.xy = FetchNormalMap( wavesSampler, IN.causticTC0.xy + wave.xy).xy;     // 1 tex + 2 alu
  causticMapR.xy += FetchNormalMap(wavesSampler, IN.causticTC0.wz + wave.xy).xy;     // 1 tex + 3 alu
   
  // fast normalize  
  causticMapR.xy = causticMapR.xy - 1.0;                                                            // 1 alu
  causticMapR.z = sqrt(1.0 - dot(causticMapR.xy, causticMapR.xy));                                  // 2 alu    
  
  half2 causticHighFreq = 0;
  causticHighFreq = FetchNormalMap( wavesSampler, IN.causticTC1.xy + wave.xy ).xy;   // 1 tex  + 1 alu
  causticHighFreq += FetchNormalMap( wavesSampler, IN.causticTC1.wz + wave.xy ).xy;   // 1 tex  + 2 alu
  causticHighFreq = causticHighFreq * 2.0 - 2.0;                                                    // 1 alu

  causticMapR.xy += causticHighFreq;  

  // Caustics sampler contains function: abs( 1-(abs( a) + abs(b))*0.5 ), which generates nice sharp pattern  
  half3 cCaustic;
  cCaustic.x = tex2D(causticsSampler, causticMapR.xy*0.55+0.55).x;
  cCaustic.y = tex2D(causticsSampler, causticMapR.xy*0.525+0.525).x;
  cCaustic.z = tex2D(causticsSampler, causticMapR.xy*0.5+0.5).x;
  
  float slice_pos = PI_GodRaysParamsPS.z * PI_GodRaysParamsPS.w;    
  
  // sharpen up a bit
  cCaustic *= cCaustic;
  
  // add very sharp highlight
  const half cMaxHightVis = 10.0;
  half fHighlightAtten =  1;//cMaxHightVis / (CausticParams.x - IN.vPosition.z);                         // 2 alu    
  fHighlightAtten = saturate( fHighlightAtten ) * min( abs( fHighlightAtten ), 2);  
  
  half fAtten =1;// saturate( (CausticParams.x - IN.vPosition.z)*4 );                                          // 2 alu  
  
  cCaustic += pow( cCaustic, 8 );
  
  half4 cScreen =  tex2D(screenMapSampler, IN.baseTC.xy);
  cScreen.xyz = cCaustic * PI_GodRaysParamsPS.w  * PI_GodRaysParamsPS.y * saturate( CausticParams.y  )* 0.25;
  
  
  half fDistToCam = length( WorldViewPos.xyz - IN.vPosition.xyz );                                      // 2 alu
  
  // 4 alu
    
  fAtten *= ( slice_pos );
  
  cScreen.xyz *= fAtten *fHighlightAtten;
  
  OUT.Color = cScreen;

  return OUT;
}

pixout UnderwaterGodRaysFinalPS(vtxOut IN)
{
  pixout OUT;

  half4 c0 = tex2D(screenMapSampler, IN.baseTC.xy);
  float anim = frac(AnimGenParams*0.01);  
  float3 vec = normalize(float3(IN.baseTC.xy *2-1, 1));
  half4 cBumpy = tex2D(underwaterBumpSampler, IN.baseTC.xy*0.025 + anim )*2-1;
  cBumpy += tex2D(underwaterBumpSampler, IN.baseTC.yx*0.033 - anim )*2-1;
  cBumpy.xyz = normalize( cBumpy ).xyz;
      
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy + cBumpy.xy*0.0125);  
  half4 cCaustics = tex2D(screenMapScaledSampler_d4, IN.baseTC.xy + cBumpy.xy*0.01);
          
  OUT.Color = cScreen + cCaustics;

  return OUT;
}
 
////////////////// technique /////////////////////

technique UnderwaterGodRays
{
  pass p0
  {
    VertexShader = compile vs_Auto UnderwaterGodRaysVS();
    PixelShader = compile ps_Auto UnderwaterGodRaysPS();    
    CullMode = None;        
  }
}

technique UnderwaterGodRaysFinal
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto UnderwaterGodRaysFinalPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Volumetric scattering technique ////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4 PI_volScatterParamsVS;
float4 PI_volScatterParamsPS;
float4 VolumetricScattering;  // x: tilling, y: speed
float4 VolumetricScatteringColor; 

sampler3D volumeMapSampler = sampler_state
{  
  Texture = textures/defaults/Noise3D.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
  AddressW = Wrap;
};


struct vtxOutVolumetricScattering
{
  float4 HPosition  : POSITION; 
  float4 baseTC    : TEXCOORDN; // zw unused
  
  float4 vPosition0 : TEXCOORDN;  // w unused   
  float4 vPosition1 : TEXCOORDN;  // w unused   
};

/// Samplers ////////////////////////////

vtxOutVolumetricScattering VolumetricScatteringVS(vtxIn IN)
{
  vtxOutVolumetricScattering OUT = (vtxOutVolumetricScattering)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy + g_VS_ScreenSize.zw * float2(0, 8))*2 - 1 ; // hack vertical position- somehow wrong offset check later
  
  // Increase each slice distance
  vPos.z = 0.5 + 0.5*saturate(PI_volScatterParamsVS.z * PI_volScatterParamsVS.w);;
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(vpGodMatrixI, vPos );
  vPos /= vPos.w;
 
  OUT.HPosition = mul(vpGodMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.baseTC.y =  1 - OUT.baseTC.y;
  
  vPos *= VolumetricScattering.x;
  g_VS_AnimGenParams.w *= VolumetricScattering.y;
  
  OUT.vPosition0.xyz = vPos*0.1 + g_VS_AnimGenParams.w *0.2;
  OUT.vPosition1.xyz = vPos*0.11 - g_VS_AnimGenParams.w *0.3;
    
  return OUT;
}

///////////////// pixel shader //////////////////

pixout VolumetricScatteringPS(vtxOutVolumetricScattering IN)
{
  pixout OUT;
  
  half4 cScreen;
  float fVolume = 1 - abs(tex3D(volumeMapSampler, IN.vPosition0 ).w*2-1);
  fVolume += 1 - abs(tex3D(volumeMapSampler, IN.vPosition1).w*2-1);
  fVolume *=0.5;
    
  fVolume *= fVolume;
  fVolume *= fVolume;
  fVolume *= fVolume;
  //fVolume *= fVolume;
  
  OUT.Color = fVolume * PI_volScatterParamsPS.w  * PI_volScatterParamsPS.y * CausticParams.y * VolumetricScatteringColor;

  return OUT;
}

pixout VolumetricScatteringFinalPS(vtxOut IN)
{
  pixout OUT;
  
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy);  
  half4 cVolume = tex2D(screenMapScaledSampler_d4, IN.baseTC.xy);

  OUT.Color = cScreen + cVolume;

  return OUT;
}

////////////////// technique /////////////////////

technique VolumetricScattering
{
  pass p0
  {
    VertexShader = compile vs_Auto VolumetricScatteringVS();
    PixelShader = compile ps_Auto VolumetricScatteringPS();    
    CullMode = None;        
  }
}

technique VolumetricScatteringFinal
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto VolumetricScatteringFinalPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Distant rain technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 mComposite  : PI_Composite; // View*Projection
float4x4 mUnproject  : PB_UnProjMatrix; // invert( View * projection )
float4 cRainColor;
float4 PI_RainParamsVS;
float4 PI_RainParamsPS;

struct vtxOutDistantRain
{
  float4 HPosition  : POSITION; 
  float4 vPosition : TEXCOORDN;  // w unused   
  float4 vPosition2 : TEXCOORDN;  // w unused   
  float4 tcProj     : TEXCOORDN;
};

/// Samplers ////////////////////////////

vtxOutDistantRain DistantRainVS(vtxIn IN)
{
  vtxOutDistantRain OUT = (vtxOutDistantRain)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy *2 - 1);
  
  vPos.xy *= 1.2; // hack: make sure to cover entire screen
  
  // Increase each slice distance
  //vPos.z = 0.1+ 0.88 * saturate(vsParams[0].z * vsParams[0].w);
  
  //vPos.z = 0.99+ 0.0025 * saturate(vsParams[0].z * vsParams[0].w);
  vPos.z = 0.005+0.99+ 0.0025 *  saturate((PI_RainParamsVS.z * PI_RainParamsVS.w ));//*saturate(vsParams[0].z * vsParams[0].w);
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(mUnproject, vPos );
  vPos /= vPos.w;
  vPos.w = 1.0;

 
  OUT.HPosition = mul(mComposite, vPos);  
  //OUT.HPosition.z = 0;
  

  OUT.tcProj = HPosToScreenTC( OUT.HPosition );

  OUT.vPosition.xyz = vPos + PI_RainParamsVS.x * float3(0, 0, 100*g_VS_AnimGenParams.x* ((PI_RainParamsVS.w*0.5+0.5)));
  OUT.vPosition2.xyz = vPos+ PI_RainParamsVS.x * float3(0, 0, 500*g_VS_AnimGenParams.x* ((PI_RainParamsVS.w*0.5+0.5)));
  OUT.vPosition.w = 1;
  OUT.vPosition2.w = 1;
    
  // Generate projection matrix based on sun direction  
  float3 dirZ = -g_VS_SunLightDir;
  float3 up = float3(0,0,1);
  float3 dirX = normalize(cross(up, dirZ));
  float3 dirY = normalize(cross(dirZ, dirX));

  float3x3 mLightView;
  mLightView[0] = dirX.xyz;
  mLightView[1] = dirY.xyz;
  mLightView[2] = dirZ.xyz;
   
  // Output caustics procedural texture generation 
  float2 uv = OUT.vPosition.xy; //mul(mLightView, OUT.vPosition.xyz).xy*0.5;

  OUT.vPosition.w =  vPos.z;//uv * 0.01 * 0.5 *2+ g_VS_AnimGenParams.w * 0.1;


  return OUT;
}

///////////////// pixel shader //////////////////

pixout DistantRainPS(vtxOutDistantRain IN)
{
  pixout OUT;
    
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  //OUT.Color = tex2D(screenMapSampler, IN.baseTC.xy);
#endif
        
  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Simulate distant rain with 3 noisy layers

  OUT.Color = saturate(tex3D( volumeMapSampler, IN.vPosition.xyz*0.45*float3(1,1,0.05)*0.1).w)*0.025*4;
  OUT.Color += saturate(tex3D( volumeMapSampler, IN.vPosition.xyz*0.3*float3(1.1,2.09,0.34)*0.1).w*2-0.8)*0.05;

  // Store current value - will be used for hits look variation
  half fHitMask = OUT.Color.x;  

  OUT.Color *= 0.5;
  OUT.Color *= saturate(tex3D( volumeMapSampler, IN.vPosition2.xyz*0.245*float3(1,1,0.1)*0.0005).w*0.5+0.5);

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Compute softintersection coeficients with surfaces and water plane

  half fSceneDepth = tex2D(depthMapSampler, IN.tcProj.xy / IN.tcProj.w).x;
  fSceneDepth += tex2D(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams0.xy).x;
  fSceneDepth += tex2D(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams0.zw).x;
  fSceneDepth += tex2D(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams1.xy).x;
  fSceneDepth += tex2D(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams1.zw).x;
  fSceneDepth *= PS_NearFarClipDist.y *0.2f;
  
  float fRainDepth = IN.tcProj.w; 	

 	half softIntersect = saturate( 0.25* ( fSceneDepth - fRainDepth ));
  float fWaterSoftIsec = saturate(0.25 * (IN.vPosition.w - g_fWaterLevel));

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Simulate surface hits/splashes
  
  // Compute ground and water plane intersection
  half fGroundHit = (1-saturate( 0.05* ( fSceneDepth - fRainDepth) ))*0.5;
  half fWaterHit = 1-saturate( 0.5* (IN.vPosition.w - g_fWaterLevel));

  // Sum up hits
  fGroundHit += fWaterHit;  

  // Apply hit mask to simulate water splashes
  fHitMask = saturate(saturate(fHitMask)*4-0.2);    
  fGroundHit *= fHitMask;


  OUT.Color += fGroundHit;

  // Apply soft-intersection with surfaces and water plane
  OUT.Color *=  (1-PI_RainParamsPS.w) *0.5 *softIntersect*fWaterSoftIsec * PI_RainParamsPS.y * cRainColor;

  return OUT;
}

pixout DistantRainFinalPS(vtxOut IN)
{
  pixout OUT;

  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy);
  half4 cRain = tex2D(screenMapScaledSampler_d2, IN.baseTC.xy);
  OUT.Color = cScreen + cRain;

  return OUT;
}

////////////////// technique /////////////////////

technique DistantRain
{
  pass p0
  {
    VertexShader = compile vs_Auto DistantRainVS();
    PixelShader = compile ps_Auto DistantRainPS();    
    CullMode = None;        
  }
}

technique DistantRainFinal
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto DistantRainFinalPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Water puddles texgen technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 waterPuddlesParams;

///////////////// vertex shader //////////////////

struct vtxOutWaterPuddles
{
  float4 HPosition  : POSITION;
  float2 baseTC    : TEXCOORDN;
  float4 noiseTC    : TEXCOORDN;  
};

vtxOutWaterPuddles waterPuddlesVS(vtxIn IN)
{
  vtxOutWaterPuddles OUT = (vtxOutWaterPuddles)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = IN.baseTC.xy;
 
  return OUT;
}

float gaussian(float d2, float radius)
{
  return exp(-d2 / radius);
  //return saturate( 1- (d2*d2/radius) );
  
}

///////////////// pixel shader //////////////////
pixout waterPuddlesPS(vtxOutWaterPuddles IN)
{
  pixout OUT;
  
  float fvar = 0;
  //float2 vDropPos = 0.5;
  float2 vDropPos = (waterPuddlesParams.xy*2-1); //0.25 * float2(cos(AnimGenParams*4 + fvar), sin(AnimGenParams*4 + fvar));
  //(frac(AnimGenParams)>=0.5) *
  
   

   float2 offsets[4] = 
   {
      1,  0,
      -1, 0,         
      0,  1,
      0, -1,
   };

   float4 c = tex2D(_tex0,  IN.baseTC).x;
   float4 d = tex2D(_tex1,  IN.baseTC).x;
   float fDilateRatio = 1.0;
   float fSpeedFactor = 0.33;//3333;
   float2 fPixSize = 1.0 / 256.0;
   float fDamping = 0.999;//95;//8;
      
   
   float4 l, r, t, b;
   l = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[0]).x;
   r = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[1]).x;
   t = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[2]).x;
   b = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[3]).x; 

   float fA = fSpeedFactor;
   float fB = 2.0 - 4.0 * fSpeedFactor;
  
   float sum = (r.x + l.x + t.x + b.x) * fA + fB * c.x - d.x;
   //float sum = (r.x + l.x + t.x + b.x) * 0.5 - d.x;
             
   OUT.Color = ( float4(sum.xxx, 1) *fDamping);  
   
   //(frac(AnimGenParams)>=0.5) *
   OUT.Color +=  waterPuddlesParams.w * gaussian( length(abs( frac(IN.baseTC.xy-vDropPos)*2-1 ) ) ,2.0/256.0 );// tex2D( _tex0, IN.baseTC.xy);

   //OUT.Color.xyz = 1-exp(-1.05*OUT.Color.x);
  
  return OUT;
}

pixout waterPuddlesDisplayPS(vtxOut IN)
{
  pixout OUT;

  float3 vWeights = 0;    
  vWeights.x = (tex2D( _tex0, IN.baseTC.xy ).x);
  vWeights.y = (tex2D( _tex0, IN.baseTC.xy + float2(1,0)/waterPuddlesParams.w).x);
  vWeights.z = (tex2D( _tex0, IN.baseTC.xy + float2(0,1)/waterPuddlesParams.w).x);
  
  // make it a bit sharper (maybe add a sharpening control)
  vWeights = ( vWeights *2 - 1 );
      
  float3 vNormal = float3( vWeights.x - vWeights.y, vWeights.x - vWeights.z,1);                  // 2 inst
  vNormal = normalize(vNormal.xyz);                                                              // 3 inst
 
  OUT.Color.xyz =vNormal*0.5+0.5;// tex2D( _tex0, IN.baseTC.xy);
  OUT.Color.w = vWeights.x*0.5+0.5;

  return OUT;
}

////////////////// technique /////////////////////

technique WaterPuddlesGen
{
  pass p0
  {
    VertexShader = compile vs_Auto waterPuddlesVS();
    PixelShader = compile ps_Auto waterPuddlesPS();    
    CullMode = None;    
  }
}

technique WaterPuddlesDisplay
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();
    PixelShader = compile ps_Auto waterPuddlesDisplayPS();    
    CullMode = None;    
  }
}

#if %DYN_BRANCHING_POSTPROCESS

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Fillrate Profile technique /////////////////////////////////////////////////////////////////////////

pixout FilrateProfilePS(vtxOut IN)
{
  pixout OUT;
  
  const int nSamples = 32;
  float fRecipSamples = 1.0 / (float) nSamples ;
  
  half4 acc = 0;
#if D3D10
  [unroll]
#endif
  for(int n = 0; n < nSamples; n++)
  {
    acc += tex2D(_tex0, IN.baseTC.xy) + (frac(n * fRecipSamples*10)*2-1)*4;
  }

  OUT.Color = acc * fRecipSamples;

  return OUT;
}

////////////////// technique /////////////////////

technique FillrateProfile
{
  pass p0
  {
    VertexShader = compile vs_3_0 BaseVS();            
    PixelShader = compile ps_3_0 FilrateProfilePS();
    CullMode = None;        
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Grain filter technique /////////////////////////////////////////////////////////////////////////

sampler2D grainNoiseSampler = sampler_state
{
  Texture = textures/defaults/vector_noise.dds;
  MinFilter = POINT;  
  MagFilter = POINT;
  MipFilter = POINT; 
  AddressU = Wrap;
  AddressV = Wrap;
};


pixout GrainFilterPS(vtxOut IN)
{
  pixout OUT;
  
  
  half4 acc = 0;

  float2 vNoiseTC = (IN.baseTC.xy ) * (PS_ScreenSize.xy/64.0) +  (psParams[0].xy/PS_ScreenSize.xy);
  float2 vNoise = tex2D(grainNoiseSampler, vNoiseTC)+ dot(IN.baseTC.xy, 1) * 65535;
  vNoise = frac( vNoise );

  vNoise = vNoise*2-1;
  //vNoise *= 0.05;

  half4 cScreen = tex2D(screenMapSampler, IN.baseTC);

  OUT.Color = cScreen + dot(vNoise.xy, 0.5)*psParams[0].w;


  return OUT;
}

////////////////// technique /////////////////////

technique GrainFilter
{
  pass p0
  {
    VertexShader = compile vs_Auto BaseVS();            
    PixelShader = compile ps_Auto GrainFilterPS();
    CullMode = None;        
  }
}

/////////////////////// eof ///
